In a very conventional pattern, you have a list of posts at /posts and a detail view at /posts/1. If you have an API server on the backend and React+Redux on the frontend, you probably fetch resources when you reach /posts. But what do you do when you reach /posts/1? If you landed /posts/ first, you already have all the resources, so you can maybe do the following:
posts reducer that returns all the posts we fetched from API servercurrentPost reducer that returns only the relevant postTo set currentPost you can dispatch an action that updates currentPost as soon as you click a post in the index view.
But if you landed /posts/1 without going to the index page, or refreshed /posts/1, you don't have the resources that you load in the index page (i.e. posts reducer returns []). To solve this, you can request /posts/1 from the API server and set currentPost then.
Question: Did I understand the flow correctly? I am not sure if currentPost reducer is even necessary. Also, I am not sure if it's conventional to use the resources from the index page and request a single resource only when it's necessary.
If you get all data you need to display currentPost in /posts request, will be sufficient to have one reducer to avoid duplicating items.
In postsReducer you need to handle two actions:
1. When you get all posts from server, your reducer should return them.
2. When you get a particular post, just append him to all posts list and return resulting array.
//reducers.js
function postsReducer(state = [], action) {
switch (action.type) {
case 'RECEIVE_POSTS':
return action.posts;
case 'RECEIVE_POST':
return [...state, action.post]
default:
return state;
}
}
PostContainer should dispatch an action to fetch currentPost. When currentPost post data will be fetched from server, you can pass it to your Post presentational component.
// PostContainer.js
class PostContainer extends Component {
componentWillMount() {
if (!this.props.post) {
this.props.dispatch(loadPost(this.props.params.id));
};
}
render() {
return (
<Post post={this.props.post}
);
}
}
function mapStateToProps(state, ownProps) {
// if you're using react-router, post id will be in `params` property.
const id = ownProps.params.id;
return {
post: state.posts.filter(post => post.id === id)[0]
};
};
export default connect(mapStateToProps)(PostContainer);
PostsListContainer should dispatch action to fetch all posts from server. When request finished successfully, you will pass array with posts to PostsList component.
// PostsListContainer.js
class PostsListContainer extends Component {
componentWillMount() {
if (!this.props.posts) {
this.props.dispatch(loadPosts());
}
}
render() {
return (
<PostsList posts={this.props.posts}
);
}
}
function mapStateToProps(state) {
return {
posts: state.posts
}
};
export default connect(mapStateToProps)(PostsListContainer);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With