useSelector with React.memo vs connect

useSelector with React.memo vs connect

参考自link。 https://react-redux.js.org/next/api/hooks#performance

据我所知,useSelector 钩子的好处是避免 wrapper hellWrapper hell 由于使用 connect HOC 正在发生。如果由于性能原因我们必须将 React.memo HOCuseSelector 一起使用,那么简单地使用 connect 会更好吗? HOC 代替?因为在任何情况下,我们都必须处于 包装器的地狱 。如果 hell 不是 connect 那么就会是 React.memo.

任何人都请解释 React.memo 相对于 connect 的好处。

好吧,首先,虽然 React.memo 是一个 HOC,但它并不创建与 connect 相同的嵌套。我创建了一个测试代码:

    import React from "react";
    import ReactDOM from "react-dom";
    import {connect, Provider} from 'react-redux'
    import { createStore } from 'redux'
    import "./styles.css";
    
    const MemoComponent = React.memo(function MyMemo() {
      return <div>Memo</div>;
    });
    
    const ConnectedComponent = connect(null,null)(function MyConnected() {
      return <div>ReduxConnectComponent</div>;
    })
    
    const store = createStore(()=>{},{})
    
    
    function App() {
      return (
        <Provider store={store}>
          <MemoComponent />
          <ConnectedComponent/>
        </Provider>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);

这是呈现的结构:

我们可以看到 connect 的内容渲染得更深了。

其次,文档说:

by default useSelector() will do a reference equality comparison of the selected value when running the selector function after an action is dispatched, and will only cause the component to re-render if the selected value changed. However, unlike connect(), useSelector() does not prevent the component from re-rendering due to its parent re-rendering, even if the component's props did not change.

这意味着当商店的不相关部分发生变化时,useSelector 的组件将不会re-rendered。这是优化中最重要的部分。是否使用 React.memo 进行优化现在完全取决于您的决定,在大多数情况下,根本不需要它。我们仅在组件渲染成本非常高的情况下才使用 React.memo。

总而言之,需要连接包装器才能连接到商店。使用 useSelector 我们不必再换行了。在极少数情况下,当我们需要优化一些重量级组件时,我们仍然需要使用 React.memo 进行包装。 React.memo 的工作也是由 connect 完成的,但在大多数情况下,这是过早的优化。

我已经尝试了很长一段时间的答案,但我得到的答案并不明确。虽然 Redux 文档中的理论并不复杂:useSelector 使用严格相等 === 而 connect 使用浅相等来确定。因此,在这两种情况下,如果您是 "pulling" 来自 Redux 状态(数字、字符串、布尔值)的原始值,您将获得相同的结果。如果值没有改变 none 的组件将重新呈现。如果你是 "pulling" 非基元(数组或对象)并且两种情况下的值都没有改变(useSelector,connect),那么使用 useSelector 的组件仍然会重新渲染 [] === [] 将始终为 false,因为它们引用不同的数组,而 connected 组件将不会重新呈现。现在为了使 useSelector 的行为相似而不是重新渲染,您可以这样做: const object = useSelector(state => state.object, shallowEqual) 您可以从 react-redux 导入 shallowEqual。或者通过使用 reselect 库来使用该状态的记忆版本:

const makeGetObject = () => createSelector(state => state.object, object => object)

并将其添加到您的选择器中,例如:const object = useSelector(state => state.object, makeGetObject); 我在试图找到它的底部时创建了这个代码框(检查 WithUseSelector 组件中的注释):useSelector vs connect()

我刚刚定制了 useSelector 钩子来避免这种情况,而且效果很好

import { useSelector, useDispatch } from 'react-redux'
import { _lodash } from '../../../lodash'

export const useCloneSelector = (selector = (obj) => obj) => {
  const selectWithClonedState = (state = {}, ...others) => selector(_lodash.cloneDeep(state), ...others)
  return useSelector(selectWithClonedState, _lodash.isEqual)
}

export { useDispatch, useSelector }