在React中访问条件渲染的画布元素以进行绘制

时间:2018-12-20 11:44:57

标签: javascript reactjs chart.js

我对React还是比较陌生,在尝试将第三方绘图库集成到我的应用程序(在这种情况下为chartjs)中感到困惑。 (注意:我在这里查看过类似的问题,但无法从中找到解决方案)

我需要创建一个以HTML canvas元素为背景的绘图实例。我正在使用React的ref道具来尝试实现此行为,但我认为我被React方法的异步性绊倒了。看来ctx.currentrender()方法中始终为空。我也尝试过将chart()调用放在componentDidMount中,但是this.ctx是未定义的,大概是因为条件渲染尚未发生,所以ref不存在?

任何帮助将不胜感激!

class Hello extends React.Component {
    constructor(props) {
        super(props);

        this.state = {data: [], labels: []}

        this.ctx = React.createRef();

        this.fakeAPICall();
    }

    // retrieve fascinating data...
    fakeAPICall = () => {
        setTimeout(() => {
            console.log('Data fetched');
            this.setState({
                data: [1,2,3],
                labels: ['A', 'B', 'C']
            })
        }, 1500);
    }

    chart = () => {
        console.log('creating chart')
        const myChart = new Chart(this.ctx, {
            type: 'bar',
            data: {
                labels: this.state.labels,
                datasets: [{
                    label: 'Series 1',
                    data: this.state.data
                }]
            }
        })
    }

    render() {
        if(this.ctx && this.ctx.current) this.chart();

        return (
            <div>
                <h1>Fascinating Chart</h1>
                {
                    this.state.data.length
                        ?
                        <canvas
                            ref={c => {
                                this.ctx = c.getContext('2d')}
                            }
                            style={{ width: 400, height: 200 }}
                        />
                        :
                        <p>Loading ...</p>
                }
            </div>
        );
    }
}

ReactDOM.render(
    <Hello name="World" />,
    document.getElementById('container')
);

我目前的最佳尝试附在这里:https://jsfiddle.net/69z2wepo/327056/

1 个答案:

答案 0 :(得分:1)

它不起作用,因为在将引用分配给canvas之后,没有其他状态更新了;这意味着不再需要重新渲染(对render方法的调用),因此您永远不必执行this.chart()。与其在render中调用最后一个方法,不如将其添加到setState中的fakeAPICall回调中:

this.setState({
    data: [1,2,3],
    labels: ['A', 'B', 'C']
}, () => this.chart());

setState完成并重新渲染组件后,将执行回调。您可以阅读有关状态回调here的更多信息。