24

I have a parent and a child component, I want to access the ref of an element which is in the child component, in my parent component. Can I pass it with props?

// Child Component (Dumb):
export default props =>
    <input type='number' ref='element' />

// Parent Component (Smart):
class Parent extends Component {
    constructor(props) {
        super(props);
    }

    componentDidMount() {
        const node = this.refs.element; // undefined
    }

    render() {
        return <Dumb { ...this.props }/>
    }
}
Jalal
  • 334
  • 1
  • 4
  • 16
Nick1R1
  • 255
  • 1
  • 2
  • 5

5 Answers5

44

You could use the callback syntax for refs:

// Dumb:
export default props =>
    <input type='number' ref={props.setRef} />

// Smart:
class Parent extends Component {
    constructor(props) {
        super(props);
    }

    setRef(ref) {
        this.inputRef = ref;
    }

    render(){
        return <Dumb {...this.props} setRef={this.setRef} />
    }
}
TimoStaudinger
  • 41,396
  • 16
  • 88
  • 94
  • I would prefer to use callback instead of passing ref to children component, because you are holding the reference to the parent component. For the simple component works fine but for the large / complicated component as per best practice you should be using callback . – Khalid Azam Mar 27 '17 at 17:25
  • @Timo Is there also a way to reference ref in the Dumb component too? – Anil Namde Jul 05 '18 at 10:31
  • @timo use ref into the Dumb component, this only works dom elements, Dumb components has not intances thats why he send the DOM into Dumb to the parent. – elporfirio Sep 01 '18 at 15:59
  • 1
    How can I give an `onChange()` to `` inside `` compnent and get the `ref` inside the `onChange` function definition at parent component? – Hareesh May 09 '19 at 06:54
13

With react^16.0.0 you would use React.createRef(). Using @Timo's answer, it would look like this:

// Dumb:
export default props =>
    <input type='number' ref={props.setRef} />

// Smart:
class Parent extends Component {
    constructor(props) {
        super(props);
        this.ref1 = React.createRef()
    }

    render(){
        return <Dumb {...this.props} setRef={this.ref1} />
    }
}
bbrinx
  • 846
  • 8
  • 14
3

As per DOC:

You may not use the ref attribute on functional components because they don't have instances. You should convert the component to a class if you need a ref to it, just like you do when you need lifecycle methods or state.

So i think, if you want to use the ref, you need to use class.

Check this: https://github.com/facebook/react/issues/4936

Mayank Shukla
  • 100,735
  • 18
  • 158
  • 142
3

If you need dynamic refs, because you have an array or something, like I did. Here is what I came up with after reading the answers above.

Also this assumes the myList is an array of objects with a key property. Anyways you get it.

Also this solution works without any issues from TypeScript as well.

const Child = props => <input ref={refElem => setRef(props.someKey, refElem)} />

class Parent extends Component {

    setRef = (key, ref) => {
      this[key] = ref; // Once this function fires, I know about my child :)
    };

    render(){
        return (
          {myList.map(listItem => <Child someKey={listItem.key} setRef={this.setRef} />)}
        )
    }
}

Anyways hope this helps someone.

Thomas Valadez
  • 1,697
  • 2
  • 22
  • 27
0
const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;

Link

https://legacy.reactjs.org/docs/forwarding-refs.html

Hyzyr
  • 568
  • 4
  • 13