Search code examples
reactjsreduxasync-awaitreact-redux

get updated state in function after dispatch React Redux


I have an Input like this below and firstly when I click on it I need to change a state of filters in Redux memory. After that I want to read that changed state inside onFilterClick function and fetch filtered items by backend API. How can I do this so: after changing the states in the redux, the current state in onFilterClick is read?

I tried to do dispatch(changeState(...)).then(() => onFilterClick(...)) but it still doesn't see the current state.

const { currentFilters } = useSelector((state) => state.filtersSlice);
const dispatch = useDispatch();
let history = useHistory();

<StyledInput
          type="checkbox"
          onChange={() => {
            dispatch(
              changeState({
                filterType: filterType.name,
                id: text,
                input: filterType.input,
              })
            );
            onFilterClick(
              currentFilters,
              dispatch,
              history
            );
          }}
          checked={checked.includes(text)}
        />

Solution

  • The current issue that you have is that currentFilters is not up to date after the dispatch because it keep the previous reference, You have multiple possibilities to fix this:

    Using a thunk

    export const stuff = (filterType, text, history): AppThunk => (dispatch, getState) => {
      // Step 1 you dispatch
      dispatch(
        changeState({
          filterType: filterType.name,
          id: text,
          input: filterType.input,
        })
      );
      // Step 2 you call a selector with a fresh state
      const currentFilters = currentFiltersSelector(getState())
      // Step 3 you call `onFilterClick` (this can be a thunk on it's own as it use dispatch)
      onFilterClick(
        currentFilters,
        dispatch,
        history
      );
    }
    

    Using hooks

    const { currentFilters } = useSelector((state) => state.filtersSlice);
    const dispatch = useDispatch();
    let history = useHistory();
    
    const onFilterClikCallback = useCallback((filters) => {
      onFilterClick(
        filters,
        dispatch,
        history
      );
    }, [history]);
    
    useEffect(() => {
      // When filters change call onFilterClikCallback
      onFilterClikCallback(currentFilters)
    }, [currentFilters])
    
    <StyledInput
              type="checkbox"
              onChange={() => {
                dispatch(
                  changeState({
                    filterType: filterType.name,
                    id: text,
                    input: filterType.input,
                  })
                );
              }}
              checked={checked.includes(text)}
    />
    

    Note: I do not know what onFilterClick do in your app but this can be a thunk on it's own

    Note: The first approach might be better as you'll do this logic outside of react and you not rely on state update to trigger it.