Question: isn't it an anti-pattern to pass component props/state via location.state
? May you suggest a better way?
I have some social site, where each user may create his own profile. Each profile is an UserProfile
component, which are routed like:
ReactDOM.render((
<Router history={History}>
<Route path="/" component={App}>
<IndexRoute component={Welcome} />
<Route path="profile" component={UserProfile} />
</Route>
</Router>
), document.getElementById('app'));
And I need to make a redirect on user click to specific user profile from multiple places of my site. I do that like:
// Where server response contains username, surname, some counters etc.
Service.getUserSummary(userId).then(response => {
History.pushState(reponse, '/profile');
});
And retrieve response
at UserProfile
:
module.exports = React.createClass({
render() {
// QUESTION: isn't it an anti-pattern? Is there any better way?
const state = this.props.location.state,
username = state.username,
............
}
})
If you deal with profiles distinguished by ID, the best way is to include the ID in the URL:
ReactDOM.render((
<Router history={History}>
<Route path="/" component={App}>
<IndexRoute component={Welcome} />
<Route path="profile/:userId" component={UserProfile} />
</Route>
</Router>
), document.getElementById('app'));
This id
will then be available inside UserProfile
as this.props.params.userId
.
A better practice is to load data from the server after the redirect, not before or during it. So, you have 3 stages of showing profile page:
UserProfile
component has been updated, and it's re-rendered with the new data.In the simplest way the data can be retrieved in componentDidMount()
method and set to the state (see https://facebook.github.io/react/tips/initial-ajax.html):
var UserProfile = React.createClass({
getInitialState: function() {
return {
data: null,
};
},
componentDidMount: function() {
// Your code for fetching user data from server:
Service.getUserSummary(this.props.params.userId).then(response => {
if (this.isMounted()) {
this.setState({
data: response.data
});
}
});
},
render: function() {
if (!this.state.data) {
// Rendering stage (2)
return (<div>Loading...</div>);
}
// Rendering stage (3)
return (
<div>
I am {this.state.data.userName}!
</div>
);
}
});