question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Share refs between sibling components

See original GitHub issue

I posted a question on Stack Overflow an hour ago which details my entire problem. So please make sure to read that.

I’ll share what I’ve tried after posting the question. I got to know about useImperativeHandle hook which allows to call a function in child component. So I gave it a shot.

App.tsx is my parent component & Konva.tsx is my child component. Konva.tsx has my canvas & App.tsx has a button to Download Image.

App.tsx

import * as React from 'react'

import { Konva } from '@/components/index'

const App = () => {
  const stageRef = React.useRef()

  return (
    <>
      <Konva className="flex-grow" ref={stageRef} />
      <button onClick={() => stageRef.current.downloadImage()}>
        Download Image
      </button>
    </>
  )
}

export default App

I used useImperativeHandle & in it I have a function downloadImage which should be called by the parent.

Konva.tsx

import * as React from 'react'
import { observer } from 'mobx-react'

import { useFrameItStore } from '@/store/index'
import { BrowserWindow } from '@/components/index'

import type { Window } from '@/types/index'
import type { Stage as StageType } from 'konva/types/Stage'

interface IProps {
  className?: string
}

interface ForwardedRef {
  downloadImage: Function
}

export const Konva = observer(
  React.forwardRef<ForwardedRef, IProps>(
    ({ className }: IProps, forwardedRef) => {
      const frameItStore = useFrameItStore()
      const browser: Window = frameItStore.browser

      const stageRef = React.useRef<StageType>(null)

      React.useImperativeHandle(
        forwardedRef,
        () => ({
          downloadImage: () =>
            stageRef.current
              ?.getStage()
              .toDataURL({ mimeType: 'image/jpeg', quality: 1 }),
        }),
        []
      )

      return (
        <Stage
          width={browser.width}
          height={browser.height}
          ref={stageRef}
          className={className}
        >
          <Layer>
            <BrowserWindow />
          </Layer>
        </Stage>
      )
    }
  )
)

However, I get 2 TS errors which I’m not sure how to solve:

First is in App.tsx on ref in <Konva /> component

Type ‘MutableRefObject<undefined>’ is not assignable to type ‘((instance: ForwardedRef | null) => void) | RefObject<ForwardedRef> | null | undefined’. Type ‘MutableRefObject<undefined>’ is not assignable to type ‘RefObject<ForwardedRef>’. Types of property ‘current’ are incompatible. Type ‘undefined’ is not assignable to type ‘ForwardedRef | null’.

Second is on stageRef in the same file

Object is possibly ‘undefined’.

Basically, I have a sibling to Konva.tsx called Options.tsx where I’ll be calling Download Image but I’ve simplified it for now to call it in App.tsx but I think it should be easy enough to move it to the child once I figure this thing out.

I also have a MobX store where I used to keep this downloadImage function as I’ve described it on StackOverflow but I thought that was unnecessary.

Any other answers appreciated. I’m not sure if this is the correct way so any help is good 😃

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
lavrtoncommented, Dec 28, 2020

Property ‘downloadImage’ does not exist on type ‘never’.

Because TS doesn’t know what type you are going to use here:

const stageRef = React.useRef()

You may need something like:

const stageRef = React.useRef<{downloadImage: Function}>(null);
0reactions
deadcoder0904commented, Dec 28, 2020

Oh yes, I’m just making it valid to the question asked. For example, I still have to figure out how to pass it from App.tsx to Options.tsx & then I’ll post it 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

React.js - Communicating between sibling components
Only their parent. (Well, there is an exception: you can use the context to share information between components, but that's a more advanced ......
Read more >
Access ref method in sibling component : r/reactjs - Reddit
Hi everybody. I'm trying to figure out what is the correct way of accessing a ref method of a child component in a...
Read more >
Passing Sibling Ref Example - StackBlitz
import ReactDOM from 'react-dom';. import React from 'react';. class Parent extends React.PureComponent {. titleRef;. saveTitleRef = ref => (this.
Read more >
React: Component Communication between Sibling ... - Medium
Generally, we apply assigning callback and props to implement communication between components in React. However, sometimes it's hard to ...
Read more >
Passing data between sibling components in React using ...
In this article I will explain how easy to send data between react sibling components using the most recent react features.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found