Search code examples
javascriptreactjscanvas

React - Can't access props


I created a React Component which has a canvas and a button. When the component mounts, an event listener is added to the button to draw something over the canvas. Also, this event listener is removed once it is executed. This Component has a prop attribute text.

<Canvas text="Hello"></Canvas>

On clicking the button, I get the following error. I'm unable to access the text prop.

TypeError
Cannot read properties of undefined (reading 'text')

Component -

import React from "react";

class Canvas extends React.Component {
  componentDidMount() {
    const canvas = this.refs.canvas;
    const button = this.refs.button;
    const ctx = canvas.getContext("2d");
    
    function action() {
      console.log("HI")
      ctx.font = "40px Consolas";
      ctx.fillStyle = "#F5F5F5";
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      ctx.fillStyle = "#000000";
      ctx.fillText(this.props.text, 10, 40);
      button.removeEventListener("click", action);
    }
    
    button.addEventListener("click", action);
  }

  render() {
    return (
      <div>
        <canvas ref="canvas" width={300} height={300} />
        <button ref="button" style={{
          display: "block",
          margin: "auto",
          marginTop: "10px"
        }}>Show</button>
      </div>
    );
  }
}
export default Canvas;


Solution

  • According to https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#other_notes:

    When attaching a handler function to an element using addEventListener(), the value of this inside the handler will be a reference to the element. It will be the same as the value of the currentTarget property of the event argument that is passed to the handler.

    You should explicitly specify this when passing it.

    Try this:

    import React from "react";
    
    class Canvas extends React.Component {
       componentDidMount() {
       const canvas = this.refs.canvas;
       const button = this.refs.button;
       const ctx = canvas.getContext("2d");
    
       function action() {
         console.log("HI")
         ctx.font = "40px Consolas";
         ctx.fillStyle = "#F5F5F5";
         ctx.fillRect(0, 0, canvas.width, canvas.height);
         ctx.fillStyle = "#000000";
         ctx.fillText(this.props.text, 10, 40);
         button.removeEventListener("click", action);
       }
       const onButtonClicked = action.bind(this)
    
       button.addEventListener("click", onButtonClicked);
      }
    
     render() {
       return (
         <div>
           <canvas ref="canvas" width={300} height={300} />
           <button ref="button" style={{
             display: "block",
             margin: "auto",
             marginTop: "10px"
           }}>Show</button>
         </div>
       );
     }
    }
    export default Canvas;