将 dom 操作放在 redux reducer 中是个坏主意吗?

Bad idea to put a dom operation inside a redux reducer?

我有几个使用相同减速器的操作,而不是在每个操作中都有一个 dom 操作,我只想在我的共享减速器中添加一次。我知道 reducer 应该是纯的(返回的数据仍然是纯的),但这是某种反模式还是可接受的策略?

 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,
      };
    ```

Redux 动作

 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,
      };

你的组件。

function YourComp(props){
  const state = useSelector(...); 

  return ( <div id="posts-cont" className={state.nomore ? 'no-more-posts' : ''} > {...}</div>

 
} 

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?

返回的数据是纯净的,但您以 DOM 突变的形式引入了 side-effect。所以这个reducer并不纯粹

这确实是一个 anti-pattern,因为现在,呈现 posts-cont 项的组件与此缩减器有一个不可见的耦合。它使您的代码库更难阅读和调试。

jinongun 的建议很好:让组件的 className 使用选择器从商店的状态中获取其值。至于一般问题

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.

永远不要在 reducer 中进行 DOM 操作。 不要做任何不是纯计算的操作。

但是您可以创建一个始终调用副作用的动作创建器(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