Cannot get an HTML element from the render() method using refs

315 views Asked by At

I'm trying to create a graphics editor with ReactJS. I have my Workspace component.This component draws objects using canvas. The Workspace component is a React class component. I cannot get an HTML element, which is in the render() method.

I could't use document.getElementById(..), I've decided to use React Refs. That's more like clean.

And I've got an error like this:

TypeError: Cannot read property 'getContext' of null

import React, { Component } from 'react';
import './Workspace.css';

// Workspace component is resposiable for drawing defferent elements on the screen
// It uses canvas API to draw elements and the stuff like that
export default class Workspace extends Component {

    constructor(props) {

        // Calling parent`s constructor function
        super(props);

        // All objects that will be drawn
        this.objects = [];

        // Creating the `canvasRef` ref for having access to the canvas element
        this.canvasRef = React.createRef();

        // Getting the canvas element, using the`canvasRef` ref
        const canvas = this.canvasRef.current;

        // Creating context
        this.context = canvas.getContext('2d');

    }

    render() {
        return (
            <div className="workspace">
                <canvas className="canvas" ref={this.canvasRef}></canvas>
            </div>
        )
    }
}
2

There are 2 answers

0
Emiel Zuurbier On BEST ANSWER

If you would read your code from top to bottom, then the canvas element wouldn't exist yet before the render method has been called. So you you have to wait for the component to actually render once to create your context.

More specifically, wait for the componentDidMount method to be called and in there, create your context.

import React, { Component } from 'react';
import './Workspace.css';

// Workspace component is resposiable for drawing defferent elements on the screen
// It uses canvas API to draw elements and the stuff like that
export default class Workspace extends Component {

    constructor(props) {

        // Calling parent`s constructor function
        super(props);

        // All objects that will be drawn
        this.objects = [];

        // Creating the `canvasRef` ref for having access to the canvas element
        this.canvasRef = React.createRef();
    }

    componentDidMount() {
        // Getting the canvas element, using the`canvasRef` ref
        const canvas = this.canvasRef.current;

        // Creating context
        this.context = canvas.getContext('2d');
    }

    render() {
        return (
            <div className="workspace">
                <canvas className="canvas" ref={this.canvasRef}></canvas>
            </div>
        )
    }
}
0
jmk On

this.canvasRef will be only accessabe in componentDidMount componentDidMount called BEFORE ref callback the accepted answer will give You more informations. Great day!