Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to call child function from parent using refs with functional component

Recently I am working on React and calling child function from parent in but when I call current on my ref it gives me undefined.

Actually refs are perfectly working for previous Parent component and even calling the useImperativeHandle functions as well but when using useImperativeHandle to call another child refs it gives undefined on current.

export const ZoneMapView = forwardRef((props,ref) => {
  const draw_map=useRef();

  useImperativeHandle(ref, () => ({
    call: ()=> {
      alert(draw_map.current);
    }
  }));
  return (
    <div className="map-view">
      <BaseMap ref={draw_map}/>
    </div>
  );
});

Call Method is being called from Parent component but then Getting undefined on alert(draw_map.current). How to access child functions ?Any Help would be appreciated

like image 716
Mohsin Mushtaq Avatar asked Aug 07 '19 07:08

Mohsin Mushtaq


People also ask

How do I access refs of a child component in the parent component?

Accessing Refs When we assign a ref to an element or child component in the render, then we can access the element using the current attribute of the ref. const element = this. myRef.

Can refs be used on functional components?

When the ref attribute is used on a custom class component, the ref object receives the mounted instance of the component as its current . You may not use the ref attribute on function components because they don't have instances.

How do you pass ref from child to parent React hooks?

The forwardRef hooks allows React users to pass refs to child components. The ref can be created and referenced with useRef or createRef and then passed in a parent component. Using forwardRef instead of useRef is useful when a ref needs to be accessed in a parent component.


Video Answer


1 Answers

I'm early in my own education of useRef and useImperativeHandle, but here's my understanding of it.

It's hard to tell from the code provided in your question how the components are setup, but it sounds like you want to call a method from a nested child component. Meaning you have a

Parent > Middle > Child

component structure, and want to call a method from Child in Parent.

To do this, you can pass the ref through the Middle component to the Child allowing the Child method to be called in the Parent.

However, it seems this could be handled in a simpler, easier to understand way - for example, using Redux, or passing a function to the child as a prop. Without seeing your full code it's hard to make recommendations.

Here's a simplified demo:

const Child = React.forwardRef((props, ref) => {
  const buttonRef = React.useRef();
  
  const handleClick = (event) => {
    console.log('button click')
  }
  
  const childStyle = {
    margin: 20
  }
  
  React.useImperativeHandle(ref, () => ({
    click: () => {
      buttonRef.current.click()
    }
  }))

  return (
    <button ref={buttonRef} style={childStyle} onClick={handleClick}>Child Component</button>
  )
})

const Middle = ({childRef}) => {
  const middleStyle = {
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    padding: 20,
    backgroundColor: 'darkgray'
  }

  return (
    <div style={middleStyle}>
      Middle Component
      <Child ref={childRef} />
    </div>
  )
}

const Parent = () => {
  const childRef = React.useRef()
  
  const parentStyle = {
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    textAlign: 'center',
    backgroundColor: 'lightgray',
    padding: 20
  }
  
  const handleMouseEnter = () => {
    /*
    *   CALL A METHOD FROM THE CHILD
    */
    childRef.current.click()
  }
  
  return (
    <div style={parentStyle} onMouseEnter={handleMouseEnter}>
      <p>
        Parent Component<br />
        onMouseEnter of this gray area the onClick of the button will be called
      </p>
      <Middle childRef={childRef} />
    </div>
  )
}

ReactDOM.render(<Parent />, document.getElementById("app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>


<div id="app"></div>
like image 83
Brett DeWoody Avatar answered Oct 23 '22 10:10

Brett DeWoody