在ReactJS中渲染/返回HTML5 Canvas

ger*_*m13 22 javascript reactjs

我正在尝试使用React渲染画布.画布内的图形也将由Reacts render方法处理.

当前代码确实使用我想要的图形渲染画布.但是我正在寻找一种方式来回报我的图形画布从内render方法.我想要这个的原因是因为我希望这个以"React Way"工作.

理想情况下,我希望我的代码是这样的:

return(
  <div>
    <canvas id='my_canvas_with_graphics_rendered_in_react'></canvas>
  </div>
);
Run Code Online (Sandbox Code Playgroud)

首先,我想知道这是否可行.或者,如果我应该寻找替代方案.

也许我错过了React的观点,如果是这样的话请告诉我.我希望有一个解决方案,因为从我读过的内容看,React将自己称为Vin MVC.这就是为什么,如果可能的话,这将是我正在尝试做的完美解决方案.我不必担心画布内的渲染.我只是将数据提供给组件,React将重新呈现更改.

我在return声明中标明了我认为正确的代码应该去的地方.

HTML代码:

<div id='wrapper'>
    <canvas id='canvas'></canvas>
</div>
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)

希望我清楚自己.

Ali*_*tor 18

你唯一的错误是你不熟悉反应参考.试试这个:

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>
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

你可能已经摆脱了ES6风格,但你明白了.因为你也可以用其他方法画画^^

  • 来自React [docs](https://facebook.github.io/react/docs/more-about-refs.html#the-ref-string-attribute)的注释:_"虽然不推荐使用字符串引用,但它们是被认为是遗留的,并且很可能在将来的某个时候被弃用.[Callback refs](https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute)是首选."_ (3认同)
  • 很好的答案,但它们现在被认为是遗产,请参阅 -&gt; https://facebook.github.io/react/docs/refs-and-the-dom.html#legacy-api-string-refs (2认同)

And*_*ahl 13

canvasrender可以执行以下操作,而不是使用您的方法:

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

你只需渲染一个空,div然后等待React挂载它.安装后,将画布附加到React创建的实际DOM节点.

原因是该render方法只返回React然后转换为真实DOM节点的虚拟DOM节点.由于您有一个真正的DOM节点,因此无法将其转换为虚拟节点.另一个原因是您应该只从render该React控件返回节点.既然你是从Reacts控件之外管理画布,你应该使用真正的DOM apis来管理它.

  • 请注意,不推荐使用React.getDOMNode():https://facebook.github.io/react/docs/component-api.html (3认同)

Red*_*att 6

关键是重写正确的React生命周期方法来进行绘制.render方法创建canvas DOM元素,你可以添加一个refs回调来设置对它的引用,但你必须等到组件被挂载才能在画布上绘制.

这是一个使用回调引用的示例,如React文档所推荐的那样.它设计用于在道具更改时基于道具和更新呈现静态(非动画)图形组件.它还订阅了窗口调整大小事件,以便可以通过CSS(例如width: 100%)动态调整大小. 此示例基于此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} />
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以secondRect从父组件设置prop或从状态设置prop以在prop更新时查看组件更新.您可以扩展此构思以构建任何类型的数据驱动的画布渲染,例如图表或图形.


mat*_*hew 6

我想我会使用 更新这个答案,React.createRef()因为this.refs现在是遗留的。Refs 和 DOM

import React from "react";
import * as PropTypes from "prop-types";

class Canvas extends React.Component {
    constructor() {
        super()
        this.canvas = React.createRef()
    }
    componentDidMount() {
        const ctx = this.canvas.current.getContext('2d')
        this.props.draw(ctx);
    }
    render() {
        return <canvas ref={this.canvas} />;        
    }
}
Canvas.propTypes = {
  draw: PropTypes.func.isRequired
};
export default Canvas
Run Code Online (Sandbox Code Playgroud)

您可以Canvas通过提供绘制上下文来使用它。

<Canvas  
  draw={ctx => {
    ctx.beginPath();
    ctx.arc(95, 50, 40, 0, 2 * Math.PI);
    ctx.closePath();
    ctx.stroke();
    }
  }
/>
Run Code Online (Sandbox Code Playgroud)