Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

useSelector hook and rerenders

-- edit -- i created a codesandbox: https://codesandbox.io/s/xenodochial-hofstadter-d3jjo

I'm starting to scratch my head and would like some help on - I assume - a simple problem.

I have a basic App component that renders a controlled text input. Once you submit this input it creates a message on the back-end, which updates a redux store. Everything seems to be working fine on this part.

My issue is when I tried to add a useEffect hook to reset the input value after a new message was added. I noticed that the useEffect that relies on [messages] is called on every render instead of just when messages changes. The simple act of typing in the input - which causes a rerender for every character - makes the hook trigger, even though it is still the same value: an empty array.

Basically I've noticed it only works as intended if my useSelector returns the same instance of an array. So if I were to read only state.messages.allIds it would work since the array does not change. But simply adding a .map(x => x) makes it return a new instance every time. I have added react-redux's shallowEqual to try and fix this, but to no avail, and I don't understand why it doesn't fix my problem.

const App = () => {
  const [message, setMessage] = useState('');
  const messages = useSelector(
    (state: RootState) => (
      state.messages.allIds.map((id: string) => state.messages.byId[id])
    ),
    shallowEqual,
  );

  useEffect(() => {
    console.log('useEffect');
  }, [messages]);

  // ...

  return (
    <form onSubmit={/* ... */}>
      <input
        onChange={event => setMessage(event.target.value)}
        value={message}
      />
    </form>
  );
}
like image 443
Nicolas SEPTIER Avatar asked Mar 16 '20 14:03

Nicolas SEPTIER


1 Answers

This maybe coming pretty late. But it might benefit others facing the same problem.

If you do not want the function to re-render on state change and only want to extract the value of a redux state variable, you may use useState

const state = useState();
const yourVariable = state.getState().reduxStateVariable;
like image 199
Prateek Ruia Avatar answered Oct 09 '22 06:10

Prateek Ruia