我在我的组件的componentWillMount调用中获取了数据(实际上是在mixin中,但想法相同)。在ajax调用返回后,我尝试设置为setState,但是出现错误消息,即未定义文档。
我不确定该如何解决。还有什么要等待的吗?一个承诺或回调我应该在其中做setState吗?
这就是我想要做的:
componentWillMount: function() { request.get(this.fullUrl()).end(function(err, res) { this.setState({data: res.body}); }.bind(this)); }
我实际上曾经遇到过类似的情况。我认为您遇到的错误是这样的:
Uncaught Error: Invariant Violation: replaceState(...): Can only update a mounted or mounting component.
该错误是由于以下事实造成的:在React组件中,无法在安装组件之前设置状态。因此,componentWillMount与其尝试在中设置状态,不如在中进行设置componentDidMount。我通常会加一张.isMounted()支票,只是为了很好。
React
componentWillMount
componentDidMount
.isMounted()
尝试这样的事情:
componentDidMount: function () { request.get(this.fullUrl()).end(function(err, res) { if (this.isMounted()) { this.setState({data: res.body}); } }.bind(this)); }
编辑: 忘记提及…如果组件在异步操作完成之前被“卸载”,则您也可能会遇到错误。
如果异步操作是“可取消的”,则可以轻松处理。假设您的request()上述superagent要求类似(可以取消),那么我将执行以下操作以避免任何潜在的错误。
request()
superagent
componentDidMount: function () { this.req = request.get(this.fullUrl()).end(function(err, res) { if (this.isMounted()) { this.setState({data: res.body}); } }.bind(this)); }, componentWillUnmount: function () { this.req.abort(); }
编辑#2: 在我们的评论之一中,您提到您的意图是创建一个可以异步加载状态的同构解决方案。虽然这超出了原始问题的范围,但我建议您检查一下react- async。开箱即用,它提供3个工具可以帮助您实现此目标。
getInitialStateAsync
var React = require('react') var ReactAsync = require('react-async') var AwesomeComponent = React.createClass({ mixins: [ReactAsync.Mixin], getInitialStateAsync: function(callback) { doAsyncStuff('/path/to/async/data', function(data) { callback(null, data) }.bind(this)) }, render: function() { ... } });
renderToStringAsync()
ReactAsync.renderToStringAsync( <AwesomeComponent />, function(err, markup, data) { res.send(markup); }) );
injectIntoMarkup()
ReactAsync.renderToStringAsync( <AwesomeComponent />, function(err, markup, data) { res.send(ReactAsync.injectIntoMarkup(markup, data, ['./app.js'])); }) );
react-async提供的功能远不止于此。您应该查看react-async文档以获取其功能的完整列表,以及对我上面简要介绍的功能的更全面的解释。
react-async