javascript - Updating a component including a canvas with React - Stack Overflow

So I'm trying to modify the state of a ponent which contains a canvas element. The canvas itself s

So I'm trying to modify the state of a ponent which contains a canvas element. The canvas itself should not update since the state affected does not affect the rendering of the canvas ?

import React from 'react';

export default class App extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            isPlaying: false
        }
    }

    handleClick() {
        this.setState({isPlaying: true});
    }

    ponentDidMount() {
        this.ctx.fillRect(50,50, 100, 100);
    }

    render() {
        return(
            <div id='container'>
                <canvas width={900} height={500}
                    ref={r => this.ctx = r.getContext('2d')}
                    onClick={() => this.handleClick()} />
            </div>
        );
    }
}

Yet an error shows up when I trigger the event onClick of the canvas :

Uncaught TypeError: Cannot read property 'getContext' of null
at ref (App.js:52)

So I'm trying to modify the state of a ponent which contains a canvas element. The canvas itself should not update since the state affected does not affect the rendering of the canvas ?

import React from 'react';

export default class App extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            isPlaying: false
        }
    }

    handleClick() {
        this.setState({isPlaying: true});
    }

    ponentDidMount() {
        this.ctx.fillRect(50,50, 100, 100);
    }

    render() {
        return(
            <div id='container'>
                <canvas width={900} height={500}
                    ref={r => this.ctx = r.getContext('2d')}
                    onClick={() => this.handleClick()} />
            </div>
        );
    }
}

Yet an error shows up when I trigger the event onClick of the canvas :

Uncaught TypeError: Cannot read property 'getContext' of null
at ref (App.js:52)
Share Improve this question asked Dec 10, 2017 at 12:37 Sara DoeSara Doe 1451 gold badge2 silver badges9 bronze badges 0
Add a ment  | 

3 Answers 3

Reset to default 1

React ponent will re-render itself on any of its state property change. If you want control on this behavior, consider overriding shouldComponentUpdate method. If you return false from this method for any state condition, your ponent will not re-render for that condition.

Now, regarding the error, you should move the arrow function definition of ref into a function reference.

The reason is, arrow function will always be passed as new instance while re-rendering, while the function reference will be passed only once during first time render.

Read more from here to know about this in more detail.

Your implementation should be as follows:

import React from "react";

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isPlaying: false
    };
    this.setContext = this.setContext.bind(this);
  }

  setContext(r) {
    console.log(r);
    this.ctx = r.getContext("2d");
  }

  handleClick(e) {
    this.setState({ isPlaying: true });

  }

  ponentDidMount() {
    this.ctx.fillRect(50, 50, 100, 100);
  }

  render() {
    return (
      <div id="container">
        <canvas
          width={900}
          height={500}
          ref={this.setContext}
          onClick={() => this.handleClick()} />
        />
      </div>
    );
  }
}

Move the Canvas to it's own class based ponent then use shouldComponentUpdate as mentioned above, if you're rendering Canvas directly in the render method of this ponent it will re-render every time something is changed, but since you need the state to be updated you can not specify which elements need to be re-rendered unless these elements are own ponents and have should ponent update. You can then pass callback functions to get ref and onClick methods.

React docs Refs Caveats explain why you get the getContext() of null.

If the ref callback is defined as an inline function, it will get called twice during updates, first with null and then again with the DOM element. This is because a new instance of the function is created with each render, so React needs to clear the old ref and set up the new one. You can avoid this by defining the ref callback as a bound method on the class, but note that it shouldn’t matter in most cases. In your case it matters since you're calling ctx.getContext("2d").

For getting rid of unnecessary renders of canvas, as already mentioned from other answers, encapsulate isPlaying in a React.PureComponent and municate changes through an onChange prop.

import * as React from 'react';

export class Canvas extends React.PureComponent {
  state = {
    isPlaying: false
  }

  handleClick(e) {
    const isPlaying = !this.state.isPlaying;
    this.setState({isPlaying});
    this.props.onChange && this.props.onChange(isPlaying)
  }

  setRef = (ctx) => {
    this.ctx = ctx.getContext("2d");
  }

  ponentDidMount() {
    this.ctx.fillRect(50, 50, 100, 100);
  }

  render() {
    return (
     <canvas
        width={900}
        height={500}
        ref={this.setRef}
        onClick={() => this.handleClick()}
      />
    );
  }
}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742412748a4439142.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信