Search code examples
reactjsreduxreact-redux

How Exactly useselector works?


As per Doc

useSelector(selector: Function, equalityFn?: Function)

useSelector accepts two params and second one is optional since by default it compare strict === reference equality check but not shallow equality.

  const state = useSelector(state => {
        console.log("useSelector rerendering");
        return state.counter
    }, shallowEqual)

Another is

  const state = useSelector(state => {
        console.log("useSelector rerendering");
        return state.counter
    })

In both Cases component rerendering when redux store state changes and also when local state changes then it will render (print console.log inside useSelector)

I really didn't understand exactly how it works

Full source code

import React, { useState } from 'react'
import { shallowEqual, useDispatch, useSelector } from 'react-redux'
import { decrement, increment } from './store/actions'


export default function CounterHooks(props) {

    const [submit, setSubmit] = useState(false)
    const state = useSelector(state => {
        console.log("useSelector rerendering");
        return state.counter
    }, shallowEqual)


    const dispatch = useDispatch()
 
    console.log("component rerendering");
    const increments = () => {

        dispatch(increment());

    }

    const decrements = () => {

        dispatch(decrement());
    }
    const submitButton = () => {
        console.log("component submit", submit);

        setSubmit((previousState) => !previousState)

    }
    return (
        <div>
            <button onClick={increments} >Incrmeent Counter</button>
            <br />
            <button onClick={decrements} >Decrement Counter</button>
            <br />
            <button onClick={submitButton} >Submit</button>
            <br />

            <h2>total : {state.count}</h2> <br />
            <h2>Submit:{String(submit)}</h2> <br />
           
           
        </div>
    )
}

MY question is how exactly second param works ?


Solution

  • In your example, it does not make a difference.

    shallowEquals makes sense when you select an object that might be similar in contents, but different by reference.

    See these two objects:

    const a = { foo: "bar" }
    const b = { foo: "bar" }
    
    console.log( a === b ) // will log false
    console.log( shallowEquals(a, b)) // will log true
    

    While a and b are two objects with similar shape and contents, they are not the same object. Now shallowEquals does a === comparison between a.foo and b.foo and since both are strings with the same content, a.foo === b.foo will be true.

    This does play a role if you create a new object in your selector, say

    const result = useSelector((state) => {
    
      return { a: state.foo.bar, b: state.baz.boo }
    
    })
    

    The result of this will always be a new object, so per default useSelector will always assume they are different, even when state.foo.bar and state.baz.boo actually did not change. If you use a shallowEqual, useSelector will look at the direct (only 1 level deep) child properties of the objects and compare those. Then it will notice that they are in fact equal and not rerender.