Search code examples
reactjsreduxreact-hooksuse-effect

useEffect loop due to useSelector updating


I have a useEffect

function Component () {
    const facets = useSelector(getFacets)

    useEffect(() => {
        dispatch(search(facets, param2, param3))
    }, [dispatch, facets, param2, param3])
    
    //rest of component with return
}

now search will actually update that facets

//Inside my slice
const search = (facets, param2, param3) => async(dispatch) => {
   //do a fetch using param2 and param3
   //fetch comes back with a facets object
   //alter response facets object based on 'old' facets
   dispatch(setFacets(newFacets)) // set the new facets
}

The issue is, when this useEffect runs, the re-render causes const facets = useSelector(getFacets) to load a new value... Linting requires I have facets as a dependency in the useEffect but putting it there means it'll just loop over and over again. How do I stop it?

I've tried pulling the logic out of a useEffect and putting it in a useCallback, but again, linting requires that I put facets as a dependency, which is basically the same exact issue.


Solution

  • Solved


    Sooooo Redux has a few store methods; dispatch being one of them. For me, the store method I was looking for was getState. More info if you look here and cmd/ctrl + F 'getState'

    I didn't think I could access the state within my slice because React would not allow me to use useSelector within the slice for obvious reasons. What was not obvious to me at the time was that I could gain access with getState

    So, the edited code would look like:

    1. remove the facets param within the component because I won't need it anymore
    function Component () {
        //const facets = useSelector(getFacets) --> NO LONGER NEEDED
    
        useEffect(() => {
            dispatch(search(/*facets, */param2, param3))
        }, [dispatch, /*facets, */param2, param3])
        
        //rest of component with return
    }
    
    1. edit the function within the slice, removing the facets param and including getState alongside dispatch
    //Inside my slice
    const search = (param2, param3) => async(dispatch, getState) => {
       //do a fetch using param2 and param3
       //fetch comes back with a facets object
       //grab 'old' facets using NEW getState and same selector: getFacets
       oldFacets = getFacets(getState())
       //alter response facets object based on oldFacets
       dispatch(setFacets(newFacets)) // set the new facets
    }
    

    Voila, no more infinite loop.