Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React - Get the ref present in child component in the parent component

I'm not trying to do anything hacky using refs. I just need the ref to the element because the element is a canvas, and to draw on a canvas you need its ref.

class Parent extends Component {
  clickDraw = () => {
    // when button clicked, get the canvas context and draw on it.
    // how?
  }

  render() {
    return (
      <div>
        <button onClick={this.clickDraw}> Draw </button>
        <Child />
      </div>
    );
  }
}


class Child extends Component {
  componentDidMount() {
    const ctx = this.canvas.getContext('2d');
    // draw something on the canvas once it's mounted
    ctx.fillStyle = "#FF0000";
    ctx.fillRect(0,0,150,75);
  }

  render() {
    return (
      <canvas width={300}
              height={500}
              ref={canvasRef => this.canvas = canvasRef}>
      </canvas>
    );
  }
}

=====

Something I tried (which technically works but feels strange) is define the <canvas> in the parent, so in its ref function, this refers to the parent component. Then I pass the <canvas> and this.canvas to the child as two separate props. I return the <canvas> (named this.props.canvasJSX) in the child's render function, and I use this.canvas (named this.props.canvasRef) to get its context to draw on it. See below:

class Parent extends Component {
  clickDraw = () => {
    // now I have access to the canvas context and can draw
    const ctx = this.canvas.getContext('2d');
    ctx.fillStyle = "#00FF00";
    ctx.fillRect(0,0,275,250);
  }

  render() {
    const canvas = (
      <canvas width={300}
              height={500}
              ref={canvasRef => this.canvas = canvasRef}>
      </canvas>
    );
    return (
      <div>
        <button onClick={this.clickDraw}> Draw </button>
        <Child canvasJSX={canvas}
               canvasRef={this.canvas} />
      </div>
    );
  }
}


class Child extends Component {
  componentDidMount() {
    const ctx = this.props.canvasRef.getContext('2d');
    // draw something on the canvas once it's mounted
    ctx.fillStyle = "#FF0000";
    ctx.fillRect(0,0,150,75);
  }

  render() {
    return this.props.canvas;
  }
}

Is there a more standard way of achieving this?

like image 730
tscizzle Avatar asked Apr 25 '17 04:04

tscizzle


2 Answers

You should actually be using the first approach and you can access the child elements refs in the parent

class Parent extends Component {
  clickDraw = () => {
    // when button clicked, get the canvas context and draw on it.
    const ctx = this.childCanvas.canvas.getContext('2d');
    ctx.fillStyle = "#00FF00";
    ctx.fillRect(0,0,275,250);
  }

  render() {
    return (
      <div>
        <button onClick={this.clickDraw}> Draw </button>
        <Child ref={(ip) => this.childCanvas = ip}/>;
      </div>
    );
  }
}


class Child extends Component {
  constructor() {
     super();
     this.canvas = null;
  }
  componentDidMount() {
    const ctx = this.canvas.getContext('2d');
    // draw something on the canvas once it's mounted
    ctx.fillStyle = "#FF0000";
    ctx.fillRect(0,0,150,75);
  }

  render() {
    return (
      <canvas width={300}
              height={500}
              ref={canvasRef => this.canvas = canvasRef}>
      </canvas>
    );
  }
}

You can only use this approach is the child component is declared as a class.

like image 191
Shubham Khatri Avatar answered Oct 23 '22 16:10

Shubham Khatri


If it cannot be avoided the suggested pattern extracted from the React docs would be:

import React, {Component} from 'react';

const Child = ({setRef}) => <input type="text" ref={setRef} />;

class Parent extends Component {
    constructor(props) {
        super(props);
        this.setRef = this.setRef.bind(this);
    }
    componentDidMount() {
        // Call function on Child dom element
        this.childInput.focus();
    }
    setRef(input) {
        this.childInput = input;
    }
    render() {
        return <Child setRef={this.setRef} />
    }
}

The Parent passes a function as prop bound to Parent's this. React will call the Child's ref callback setRef and attach the childInput property to this which as we already noted points to the Parent.

like image 2
arpl Avatar answered Oct 23 '22 16:10

arpl