useSelector causing rerender despite using shallowEqual?

Viewed 2681

I have a simple App Component as below

import { useSelector, shallowEqual } from 'react-redux';

const App: React.FC = () => {
  console.log('im at App')
  const currentUser = useSelector((state) => (state.userManagement.user), shallowEqual);
  // user is an object

  return (
    <div className="App">
      <header className="App-header">
        Hello World
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/users">Users</Link>
            </li>
          </ul>
        </nav>
      </header>
    </div>
  );
}

Whenever I press on "Home" Link and navigate to the component above, I will see Im at App twice? useSelector will cause a second re-render despite I've added shallowEqual. Have I understood the concept of using this shallowEqual wrongly?

UPDATES:

I've added the suggested useEffect to debug and realized that it was being logged one time, but why im at App is being printed twice?

useEffect(() => {
    console.log("current user changed", currentUser)
  },[currentUser])

enter image description here

3 Answers

Hooks/renders can be run multiple times when in strict mode.

Adding it here as suggestion requires some code.

Just try this out to debug it. If this log is happening, it means your currentUser object is changing

useEffect(() => {
  console.log("current user changed", currentUser)
},[currentUser])

Note: This is just suggestion to debug it.

If you look into the implementation of useSelector (https://github.com/reduxjs/react-redux/blob/master/src/hooks/useSelector.js#L9) then you will find, that useSelector will not only check if the return value changes, but also if there are any changes inside the store (https://github.com/reduxjs/react-redux/blob/master/src/hooks/useSelector.js#L32).

It will by design force an update by dispatching a state update (see implementation of forceRender: https://github.com/reduxjs/react-redux/blob/master/src/hooks/useSelector.js#L15)

As much as I like the react hooks, it feels like it might be better to use the connect(mapStateToProps)(App) approach in order to avoid too many updates.

Would be interesting to understand why they implemented it in that way.

Related