React初学者咨询:Express-React股票图表应用函数执行顺序问题
根本原因
你遇到的问题核心是异步操作的执行顺序:fetchData里的xhr请求是异步任务,JavaScript在执行时不会等待这个请求完成,而是继续往下执行createChart。这时候this.state.seriesOptions还是初始的空数组,图表自然绘制不出数据;等后续异步请求完成、setState更新状态时,createChart早就执行过了,所以不会重新渲染图表。
而把createChart放在fetchData的回调里能正常工作,是因为它会等异步请求完成、数据处理完毕、state更新之后才被调用,这时候seriesOptions已经有了正确的数据。
实现独立调用createChart的解决方案
下面几种方案都能让两个函数保持职责独立,同时保证createChart在数据准备好之后执行:
方案1:利用setState的回调函数
setState支持第二个参数——一个回调函数,它会在state更新完成后触发。我们可以借助这个回调来调用createChart,这样既不把两个函数耦合在一起,又能保证执行顺序:
修改fetchData里的setState部分:
that.setState({ seriesOptions }, () => { this.createChart(); });
然后componentDidMount只需要调用fetchData即可:
componentDidMount() { this.fetchData('some stock symbol'); }
方案2:使用componentDidUpdate监听state变化
如果后续还有其他场景需要更新seriesOptions并重新绘制图表,这个方案会更灵活。通过componentDidUpdate生命周期钩子监听seriesOptions的变化,一旦它更新就自动调用createChart:
componentDidUpdate(prevProps, prevState) { // 仅当seriesOptions确实发生变化时,才重新绘制图表 if (prevState.seriesOptions !== this.state.seriesOptions) { this.createChart(); } }
此时componentDidMount只需触发数据请求:
componentDidMount() { this.fetchData('some stock symbol'); }
方案3:封装fetchData为Promise(推荐的现代写法)
把异步的xhr请求封装成Promise,再用async/await来控制流程,代码可读性会更高:
fetchData = async (symbol) => { try { const responseData = await new Promise((resolve, reject) => { const url = 'someurl'; xhr({ url: url }, function(e, d) { if (e) reject(e); else resolve(d); }); }); // 处理数据得到seriesOptions const seriesOptions = 'some operation to calculate'; this.setState({ seriesOptions }); } catch (error) { console.log(error); } }
然后修改componentDidMount为异步函数:
async componentDidMount() { await this.fetchData('some stock symbol'); this.createChart(); }
这种方式能明确保证fetchData的异步操作完成后,才执行createChart,两个函数的职责依然完全独立。
内容的提问来源于stack exchange,提问作者Guozheng Kuang

