2015-05-18 13 views
15

Sto provando a eseguire il rendering di una tela utilizzando React. La grafica all'interno della tela sarà gestita anche dal metodo Reazioni render.Rendering/Ritorno tela HTML5 in ReactJS

Il codice corrente esegue il rendering di una tela con la grafica desiderata. Ma sto cercando un modo per restituire una tela con la mia grafica dal metodo render. La ragione per cui voglio questo, è perché voglio che funzioni in "React Way".

Idealmente, vorrei che il mio codice per essere qualcosa di simile:

return(
    <div> 
    <canvas id='my_canvas_with_graphics_rendered_in_react'></canvas> 
    </div> 
); 

primo luogo, voglio sapere se questo è ancora possibile. O se dovessi cercare un'alternativa.

Forse mi manca il punto di React, se questo è il caso per favore fatemelo sapere. Spero che ci sia una soluzione, perché da quello che ho letto React si presenta come lo V in MVC. Ecco perché, se possibile, questa sarebbe una soluzione perfetta per quello che sto cercando di fare. Non dovrei preoccuparmi del rendering all'interno della mia tela. Fornirei semplicemente i dati al componente e React re-renderà le modifiche.

Ho contrassegnato di nella dichiarazione return in cui credo che il codice corretto dovrebbe andare.

Il codice HTML:

<div id='wrapper'> 
    <canvas id='canvas'></canvas> 
</div> 

Il codice jsx:

var MyCanvas = React.createClass({ 
    render:function(){ 
     var line = this.props.lines; 
     var ctx = this.props.canvas.getContext("2d"); 

     ctx.strokeStyle = 'rgba(0,0,0,0.5)'; 
     ctx.beginPath(); 
     ctx.moveTo(line[0].x0, line[0].y0); 
     // .... more code ..... 
     ctx.stroke(); 

     return(
      <div> 
       /* ********************************* 
       ??? RETURN MY RENDERED CANVAS 
        WITH GRAPHIC LINES. ???? 
      This is where I want to return the canvas 
       ********************************* */ 
      </div> 
     ); 

    } 
}); 


var wrapper = document.getElementById('wrapper'); 
var canvas = document.getElementById('canvas'); 
var line1 = { x0: 0, y0: 10, x1: 20, y1: 30 }; 
var line2 = { x0: 40, y0: 50, x1: 60, y1: 70 }; 

var myCanvas = <MyCanvas canvas={ canvas } lines={ [line1, line2] } />; 
React.render(myCanvas, wrapper); 

Speranza Mi sono spiegato.

risposta

11

Invece di usare il canvas nel metodo render, si farebbe qualcosa di simile:

var MyCanvas = React.createClass({ 
    componentDidMount: function() { 
    React.getDOMNode(this).appendChild(this.props.canvas); 
    }, 
    render: function() { 
    return <div />; 
    } 
}); 

Basta rendere un vuoto div e attendere React per montare questo. Una volta montato, aggiungi la tua tela al vero nodo DOM creato da React.

La ragione di ciò è che il metodo render restituisce solo nodi DOM virtuali che React poi traduce in veri nodi DOM. E poiché hai un vero nodo DOM, non puoi convertirlo in un nodo virtuale. Un altro motivo è che si dovrebbero restituire solo i nodi da render controllati da React. E dal momento che gestisci il canvas dall'esterno del controllo Reacts, dovresti usare le autentiche API DOM per gestirlo.

+0

Prima domanda: è importante se chiamo le mie routine di disegno grafico in 'componentDidMount' o' render'? – germ13

+0

Seconda domanda: la gestione del canvas dall'interno di React (la sua creazione e il riferimento) sarebbe più di Reacts modo di fare le cose? La mia idea è di rendere questo componente parte di un set più ampio di componenti React. – germ13

+1

Prima domanda: Sì, è importante. 'render' può essere chiamato qualsiasi numero di volte durante la vita dell'istanza del componente, mentre' componentDidMount' sarà chiamato una sola volta. Assicurati di implementare anche 'componentWillUnmount' e pulisci lì. –

16

Il tuo unico errore era che non avevi familiarità con i ref di risposta. provare questo:

class ConnectionChart extends React.Component { 

    componentDidMount() { 
     let canvas = ReactDOM.findDOMNode(this.refs.myCanvas); 
     let ctx = canvas.getContext('2d'); 

     ctx.fillStyle = 'rgb(200,0,0)'; 
     ctx.fillRect(10, 10, 55, 50); 
    } 

    render() { 
     return (
      <div> 
       <canvas ref="myCanvas" /> 
      </div> 
     ); 
    } 
} 

Potreste aver sbarazzarsi di stile ES6 ma si ottiene l'idea. La causa può dipingere anche in altri modi ^^

+3

Una nota da React [docs] (https://facebook.github.io/react /docs/more-about-refs.html#the-ref-string-attribute): _ "Sebbene gli arbitri delle stringhe non siano deprecati, sono considerati legacy e probabilmente verranno deprecati in futuro. [Callback refs] (https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute) sono preferiti. "_ –

+1

Buona risposta ma sono considerati legacy ora vedi -> https: //facebook.github.io/react/docs/refs-and-the-dom.html#legacy-api-string-refs – timebandit

5

La chiave sta ignorando i giusti metodi del ciclo di vita React per eseguire il disegno. Il metodo render crea l'elemento DOM canvas e puoi aggiungere un callback refs per impostare un riferimento ad esso, ma devi aspettare che il componente sia montato per disegnare sul canvas.

Ecco un esempio che utilizza un riferimento callback come consigliano i documenti React. È progettato per rendere un componente grafico statico (non animato) basato su oggetti di scena e aggiornamenti quando cambiano gli oggetti di scena. Si abbona anche all'evento di ridimensionamento della finestra in modo che possa essere ridimensionato dinamicamente tramite CSS (ad esempio width: 100%). This example is based on the code from this Gist.

export default class CanvasComponent extends React.Component { 

    constructor(props) { 
     super(props); 

     this._resizeHandler =() => { 
      /* Allows CSS to determine size of canvas */ 
      this.canvas.width = this.canvas.clientWidth; 
      this.canvas.height = this.canvas.clientHeight; 

      this.clearAndDraw(); 
     } 
    } 

    componentDidMount() { 
     window.addEventListener('resize', this._resizeHandler); 

     /* Allows CSS to determine size of canvas */ 
     this.canvas.width = this.canvas.clientWidth; 
     this.canvas.height = this.canvas.clientHeight; 

     this.clearAndDraw(); 
    } 

    componentWillUnmount() { 
     window.removeEventListener('resize', this._resizeHandler); 
    } 

    componentDidUpdate(prevProps, prevState) { 
     if (this.props.secondRect !== prevProps.secondRect) { 
      this.clearAndDraw(); 
     } 
    } 

    clearAndDraw() { 
     const ctx = this.canvas.getContext('2d'); 
     if (ctx) { 
      ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); 
      this.draw(ctx); 
     } 
    } 

    draw(ctx) { 
     ctx.fillStyle = 'rgb(200, 0, 0)'; 
     ctx.fillRect(10, 10, 50, 50); 

     if (this.props.secondRect) { 
      ctx.fillStyle = 'rgba(0, 0, 200, 0.5)'; 
      ctx.fillRect(30, 30, 50, 50); 
     } 
    } 

    render() { 
     return (
      <canvas ref={canvas => this.canvas = canvas} /> 
     ); 
    } 
} 

È possibile impostare l'elica secondRect dalla componente principale o impostarlo da stato a vedere l'aggiornamento dei componenti quando gli aggiornamenti prop. Puoi estendere questa idea per creare qualsiasi tipo di rendering di canvas basato su dati, ad esempio un grafico o un grafico.

+0

Ho modificato l'esempio per mostrare anche la migliore pratica di controllare se gli oggetti di scena o lo stato sono cambiati in ' componentDidUpdate' prima di ridisegnare il canvas. Se non si controlla che gli oggetti di scena o lo stato siano effettivamente cambiati, si può finire per ridisegnare il quadro molto più frequentemente del necessario. – RedMatt

Problemi correlati