2017-12-10 1 views
0

So versuche ich den Zustand einer Komponente, die ein Canvas-Element enthält, zu ändern. Der Canvas selbst sollte nicht aktualisiert werden, da der betroffene Zustand das Rendering des Canvas nicht beeinflusst.Aktualisieren einer Komponente mit einem Canvas mit React

import React from 'react'; 

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

     this.state = { 
      isPlaying: false 
     } 
    } 

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

    componentDidMount() { 
     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> 
     ); 
    } 
} 

Noch ein Fehler auftaucht, wenn ich das Ereignis onClick der Leinwand auslösen:

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

Antwort

0

Reagieren Komponente wird sich ändern auf jeder seiner Staatseigentum neu rendern. Wenn Sie dieses Verhalten steuern möchten, ziehen Sie in Betracht, die Methode shouldComponentUpdate zu überschreiben. Wenn Sie false von dieser Methode für eine beliebige state-Bedingung zurückgeben, wird die Komponente für diese Bedingung nicht erneut gerendert.

Jetzt, in Bezug auf den Fehler, sollten Sie die Pfeilfunktionsdefinition von ref in eine Funktionsreferenz verschieben.

Der Grund ist, Pfeil-Funktion wird immer als neue Instanz beim erneuten Rendern übergeben, während die Funktion Referenz nur einmal beim ersten Mal übergeben wird.

Lesen Sie mehr aus here, um mehr darüber zu wissen.

Ihre Umsetzung sollte wie folgt sein:

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

    } 

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

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

docs Reagieren Refs Caveats erklären, warum Sie die getContext() of null bekommen.

Wenn der Callback ref als Inline-Funktion definiert ist, wird er während Aktualisierungen zweimal aufgerufen, zuerst mit null und dann erneut mit dem DOM-Element. Dies liegt daran, dass mit jedem Rendern eine neue Instanz der Funktion erstellt wird, sodass React den alten Verweis löschen und den neuen Verweis einrichten muss. Sie können dies vermeiden, indem Sie den ref-Callback als gebundene Methode für die Klasse definieren, beachten Sie jedoch, dass dies in den meisten Fällen keine Rolle spielt. In Ihrem Fall ist es wichtig, dass Sie ctx.getContext("2d") anrufen.

Für unnötige loszuwerden macht von canvas, wie bereits von anderen Antworten erwähnt, kapselt isPlaying in einem React.PureComponent und kommunizieren Änderungen durch eine 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"); 
    } 

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

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

"Kann die Eigenschaft 'getContext' von null nicht lesen" hat nichts mit der onClick-Methode zu tun, und die Art, wie er handleClick verwendet, müssen Sie nicht binden, weil es eine Pfeil-basierte Funktion ist onClick –

+0

Ich habe meine geschrieben Antwort @ArberSylejmani – arpl

0

Verschieben der Leinwand seine eigene Basis Komponentenklasse dann shouldComponentUpdate verwenden, wie oben erwähnt, wenn Sie Leinwand sind Rendering direkt in der Renderverfahren dieser Komponente wird es jedes Mal etwas geändert wird neu rendern, Da der Status jedoch aktualisiert werden muss, können Sie nicht angeben, welche Elemente erneut gerendert werden müssen, es sei denn, diese Elemente sind eigene Komponenten und die Komponente muss aktualisiert werden. Sie können dann Callback-Funktionen übergeben, um ref- und onClick-Methoden zu erhalten.

Verwandte Themen