useEffect infinite loop with dependency array on redux dispatch

1.1k views Asked by At

Running into an infinite loop when I try to dispatch an action which grabs all recent posts from state.

I have tried the following in useEffect dependency array

  • Object.values(statePosts)
  • useDeepCompare(statePosts)
  • passing dispatch
  • omitting dispatch
  • omitting statePosts
  • passing statePosts
  • doing the same thing in useCallback

a lot of the suggestions came from here

I have verified that data correctly updates in my redux store.

I have no idea why this is still happening

my component

  const dispatch = useDispatch()
  const { user } = useSelector((state) => state.user)
  const { logs: statePosts } = useSelector((state) => state.actionPosts)

  const useDeepCompare = (value) => {
    const ref = useRef()
    if (!_.isEqual(ref.current, value)) {
      ref.current = value
    }
    return ref.current
  }

  useEffect(() => {
    dispatch(getActionLogsRest(user.email))
  }, [user, dispatch, useDeepCompare(stateLogs)])

actionPosts createSlice

const slice = createSlice({
  name: 'actionPosts',

  initialState: {
    posts: [],
  },
  reducers: {
    postsLoading: (state, { payload }) => {
      if (state.loading === 'idle') {
        state.loading = 'pending'
      }
    },
    postsReceived: (state, { payload }) => {
      state.posts = payload
    },
  },
})

export default slice.reducer

const { postsReceived, postsLoading } = slice.actions

export const getActionPostsRest = (email) => async (dispatch) => {
  try {
    dispatch(postsLoading())
    const { data } = await getUserActionPostsByUser({ email })
    dispatch(postsReceived(data.userActionPostsByUser))
    return data.userActionPostsByUser
  } catch (error) {
    throw new Error(error.message)
  }
}
1

There are 1 answers

11
Aleks On

Remove dispatch from dependencies.

 useEffect(() => {
    dispatch(getActionLogsRest(user.email))
  }, [user, dispatch, useDeepCompare(stateLogs)])

you cannot use hook as dependency and by the way, ref.current, is always undefined here

const useDeepCompare = (value) => {
    const ref = useRef()
    if (!_.isEqual(ref.current, value)) {
      ref.current = value
    }
    return ref.current
  }

because useDeepCompare essentially is just a function that you initiate (together with ref) on each call, all it does is just returns value. That's where the loop starts.