Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

useSelector with React.memo vs connect

referring from the link. https://react-redux.js.org/next/api/hooks#performance

what i understand the benefit of useSelector hook, is to avoid wrapper hell. Wrapper hell is happening due to the usage of connect HOC. If we have to use React.memo HOC with useSelector due to perfomance reason, would it be better approach to simply use connect HOC instead? Because in any case we would have to be in hell of wrappers. If the hell is not by connect then would be by React.memo.

Any one please explain the benefit of React.memo over connect.

like image 651
Sheikh Abdul Wahid Avatar asked Jun 11 '19 20:06

Sheikh Abdul Wahid


2 Answers

I have been trying to get an answer for quite some time but the answers I got weren't clear. Although the theory in the Redux documentation isn't complicated: useSelector uses strict equality === and connect uses shallow equality to determine. So in both cases, if you are "pulling" a primitive value from your Redux state (number, string, boolean) you will be having the same outcome. If values haven't changed none of the components will rerender. If you are "pulling" non-primitives (arrays or objects) and the values haven't changed for both cases (useSelector, connect), then the component that uses useSelector will still rerender as of course [] === [] will always be false, as they are referencing different arrays, where as the connected component will NOT rerender. Now in order to make useSelector behave similarly and not rerender, you can do this: const object = useSelector(state => state.object, shallowEqual) You can import shallowEqual from react-redux. Or alternatively use a memoized version of that piece of state by using the reselect library:

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

and add it to your selector such as: const object = useSelector(state => state.object, makeGetObject); I have created this codesandbox when I was trying to get at the bottom of it (check the comments at the WithUseSelector component): useSelector vs connect()

like image 99
Kleo Avatar answered Oct 21 '22 07:10

Kleo


Well, first, interesting enough although React.memo is a HOC it does not create the same nesting as connect does. I have created a test code:

    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);

And here is the structure rendered:

enter image description here

We can see that a content for connect is rendered deeper.

Second, the docs say:

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.

that means the component which useSelector will not be re-rendered when unrelated parts of the store change. And this is the most important part of the optimization. Whether optimizing with React.memo or not is now completely depends on your decision and in most cases, it simply is not needed. We use React.memo only in cases when the component is very expensive to render.

To summarize, connect wrapper was required to connect to the store. With useSelector we do not have to wrap anymore. We still need to wrap with React.memo in rare cases when we need to optimize some heavy components. The work of React.memo was also done by connect but in most cases, it was premature optimization.

like image 31
Oleksandr Nechai Avatar answered Oct 21 '22 07:10

Oleksandr Nechai