Reputation: 690
I have several actions which use the same reducer, and instead of having a dom operation in each of those actions, I want to just add it once inside my shared reducer. I know reducers are to be pure (which the returned data still is), but is this some kind of anti-pattern or an acceptable strategy?
case APPEND_POSTS:
!payload.length &&
document.getElementById('posts-cont').classList.add('no-more-posts'); // this
const total = state.posts.length + payload.length;
const limit = total > posts_to_keep_limit ? 50 : 0;
return {
...state,
posts: [...state.posts.slice(limit), ...payload],
loading: false,
};
```
Upvotes: 4
Views: 444
Reputation: 1382
jinongun's advice is good: let the className of the component derive its value from the store's state using a selector. AS for the general question
I have several actions which use the same reducer, and instead of having a dom operation in each of those actions, I want to just add it once inside my shared reducer.
DON'T EVER make DOM operations inside a reducer. Don't ever make any operation that is not a pure computation.
But you can create an action creator that always calls a side effect (with Redux-Thunk):
function appendPosts(payload) {
return dispatch => {
mySideEffect()
dispatch({
type: APPEND_POSTS,
payload
})
}
}
function action1(params) {
return dispatch => {
dispatch({
type: ACTION1,
payload: params
})
dispatch(appendPosts(params))
}
}
function action2(params) {
return dispatch => {
dispatch({
type: ACTION2,
payload: params
})
dispatch(appendPosts(params))
}
}
// etc
Upvotes: 1
Reputation: 15363
I know reducers are to be pure (which the returned data still is), but is this some kind of anti-pattern or an acceptable strategy?
The returned data is pure, but you've introduced a side-effect in the form of a DOM mutation. Therefore, this reducer is not pure.
This is indeed an anti-pattern because now, the component(s) that render posts-cont
items have an invisible coupling to this reducer. It makes your codebase more difficult to read and debug.
Upvotes: 3
Reputation: 10264
Redux Action
case APPEND_POSTS:
// you don't need to use below code.
// !payload.length && document.getElementById('posts-cont').classList.add('no-more-posts'); // this
const total = state.posts.length + payload.length;
const limit = total > posts_to_keep_limit ? 50 : 0;
return {
...state,
posts: [...state.posts.slice(limit), ...payload],
nomore: true,
loading: false,
};
Your component.
function YourComp(props){
const state = useSelector(...);
return ( <div id="posts-cont" className={state.nomore ? 'no-more-posts' : ''} > {...}</div>
}
Upvotes: 4