为什么当 redux reducer 不返回新数组时,react 组件可以重新渲染?

时间:2021-07-26 16:25:09

标签: reactjs redux react-redux

我们知道,如果我们想要重新渲染一个由 react-redux 连接的 react 组件,我们应该在调度相关的 action 时在 reducer 中返回一个新的数组。我的问题是当 redux reducer 不返回新数组时,为什么 react 组件可以重新渲染? 当我点击应用组件按钮时,第一个应用名称变成了'aaa',为什么???

动作:

export function setAppName(name: string) {
  return {
    type: 'SET_APP_NAME',
    name,
  }
}

减速器:

export function appInfos(state = {
  appInfos: [
    {name: 'ccc'},
    {name: 'ddd'},
  ]
}, action: any) {
  switch(action.type) {
    case 'SET_APP_NAME':
      // just return origin array, not a new array
      const appInfos = state.appInfos;
      appInfos[0].name = action.name
      return Object.assign({}, state, { appInfos })
    default:
      return state;
  }
}

组件应用:

function mapStateToProps(state: any) {
  return {
    app: state.appInfos
  }
}

function App() {
  const { app } = useSelector(mapStateToProps)
  const dispatch = useDispatch()
  const onClick = useCallback(() => {
    dispatch(setAppName('aaa'))
  }, [dispatch])

  return (
    <div className="app">
      {app.appInfos.map((info: any) => {
        return <div key={info.name}>{info.name}</div>
      })}
      <button onClick={onClick}>click</button>
    </div>
  );
}

容器和存储:

const store = createStore(combineReducers({
  appInfos
}))

ReactDOM.render(
  <Provider store={store}>
    <React.StrictMode>
    <App />
  </React.StrictMode>
  </Provider>,
  document.getElementById('root')
);

1 个答案:

答案 0 :(得分:1)

您混淆了 connectuseSelector 的使用,这导致了不必要的渲染。

connect 接受一个 mapStateToProps 函数作为参数,它必须返回一个对象,因为所有字段都将成为组件的新道具。如果任何单个字段更改为新引用,该组件将重新呈现:

https://react-redux.js.org/using-react-redux/connect-mapstate

然而,useSelector 接受一个必须返回 one 值的选择器函数,如果该 one 引用更改为新值,它将重新呈现:

https://react-redux.js.org/api/hooks#equality-comparisons-and-updates

现在,您正在编写一个总是返回一个新对象引用的函数。您的函数将总是每个分派动作后运行,因此它会总是强制组件重新渲染。

改为:

function selectAppInfo(state) {
  return state.appInfos
}
相关问题