I grab my data in my componentWillMount call of my component [actually it\'s in a mixin, but same idea]. After the ajax call returns, I attempt to setState, but I get the error
I've actually encountered a similar situation before. I assume the error you encountered was something like this:
Uncaught Error: Invariant Violation: replaceState(...): Can only update a mounted or mounting component.
The error is caused by the fact that, in React
components, you cannot set state before the component is mounted. So, instead of attempting to set the state in componentWillMount
, you should do it in componentDidMount
. I typically add an .isMounted()
check, just for good measure.
Try something like this:
componentDidMount: function () {
request.get(this.fullUrl()).end(function(err, res) {
if (this.isMounted()) {
this.setState({data: res.body});
}
}.bind(this));
}
This can be easily handled if the async operation is "cancelable". Assuming your request()
above is something like a superagent
request (which are cancelable), I would do the following to avoid any potential errors.
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();
}
getInitialStateAsync
- this is provided via a mixin, and it allows a component to fetch state data asyncrhonously.
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()
- which allows you to render server side
ReactAsync.renderToStringAsync(
,
function(err, markup, data) {
res.send(markup);
})
);
injectIntoMarkup()
- which will inject the server state, along with the markup to ensure it's available client-side
ReactAsync.renderToStringAsync(
,
function(err, markup, data) {
res.send(ReactAsync.injectIntoMarkup(markup, data, ['./app.js']));
})
);
react-async
provides far more functionality than this. You should check out the react-async documentation for a full list of its features, and a more comprehensive explanation of the ones I briefly describe above.