Search code examples
javascriptreactjsreact-refreact-class-based-component

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


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>
        )
    }
}

Solution

  • 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>
            )
        }
    }