I'm a newbie in redux and es6 syntax. I make my app with official redux tutorial, and with this example.
There is JS snippet below. My point - to define REQUEST_POST_BODY and RECEIVE_POST_BODY cases in posts reducer. Main difficult - to find and update right object in store.
I try to use code from example:
return Object.assign({}, state, { [action.subreddit]: posts(state[action.subreddit], action) })
But it used simple array of posts. It's not needed to find right post by id.
Here my code:
const initialState = { items: [{id:3, title: '1984', isFetching:false}, {id:6, title: 'Mouse', isFetching:false}] } // Reducer for posts store export default function posts(state = initialState, action) { switch (action.type) { case REQUEST_POST_BODY: // here I need to set post.isFetching => true case RECEIVE_POST_BODY: // here I need to set post.isFetching => false and post.body => action.body default: return state; } } function requestPostBody(id) { return { type: REQUEST_POST_BODY, id }; } function receivePostBody(id, body_from_server) { return { type: RECEIVE_POST_BODY, id, body: body_from_server }; } dispatch(requestPostBody(3)); dispatch(receivePostBody(3, {id:3, body: 'blablabla'}));
The only way to update a state inside a store is to dispatch an action and define a reducer function to perform tasks based on the given actions. Once dispatched, the action goes inside the reducer functions which performs the tasks and return the updated state to the store. This is what Redux is all about.
dispatch(action) Dispatches an action. This is the only way to trigger a state change. The store's reducing function will be called with the current getState() result and the given action synchronously.
To use the reducer function along with React we need to call it with one of the constants we setup, and then pass it into setState . increment = () => { this. setState( reducer({ type: INCREMENT, }) ); }; decrement = () => { this. setState( reducer({ type: DECREMENT, }) ); };
When we refresh page in a web-app, the state always resets back to the initial values which in not a good thing when you try to build some large web-app like e-commerce. We can manually do the state persistent using the native JavaScript localStorage.
If you'd prefer to stick with arrays, then you can write a reducer that just tackles single post
objects.
export default function reducePost(post, action) { if(post.id !== action.id) return post; switch(action.type) { case REQUEST_POST_BODY: return Object.assign({}, post, { isFetching: true }); case RECEIVE_POST_BODY: return Object.assign({}, post, { isFetching: false, body: action.body }); default: return post; }
Your root reducer would become:
export default function posts(state = initialState, action) { return state.map(post => reducePost(post, action); }
We're just running our new reducer over each post in the list, to return an updated array of posts. In this case, the unique id will ensure that only one item will be changed.
If each item has a unique string/number id, then you can flip your array around and use an object
instead.
const initialState = { items: { 3: {id:3, title: '1984', isFetching:false}, 6: {id:6, title: 'Mouse', isFetching:false} }; }
Then you can simplify your reducer.
switch (action.type) { case REQUEST_POST_BODY: let id = action.id; return Object.assign({}, state, { [id]: Object.assign({}, state[id], { isFetching: true }) }); case RECEIVE_POST_BODY: let id = action.id; return Object.assign({}, state, { [id]: Object.assign({}, state[id], { isFetching: false, body: action.body }) }); default: return state; }
If you're happy to experiment with some ES7 syntax too, you can enable the Object spread operator with Babel and rewrite the calls to Object.assign
.
switch (action.type) { case REQUEST_POST_BODY: let id = action.id; return { ...state, [id]: {...state[id], isFetching: true } }; case RECEIVE_POST_BODY: let id = action.id; return { ...state, [id]: { ...state[id], isFetching: false, body: action.body } }; default: return state; }
If you're not so keen on using the spread syntax, then it's still possible to make Object.assign
a bit more palatable.
function $set(...objects) { return Object.assign({}, ...objects); } case RECEIVE_POST_BODY: let id = action.id; return $set(state, { [id]: $set(state[id], { isFetching: false, body: action.body }) });
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