Redux action return type when using dispatch and getState
Asked Answered
J

2

5

I am struggling to figure out what the return type should be for my action. Everything works whilst I am using any but am trying to avoid using any.

export const saveValue = (value: number): any => {
    return (dispatch: Dispatch<SaveValue>, getState: () => State): void => {
        axios.post('www.exampleurl.com', value)
            .then((response) => {
                const someValueFromState = getState().stateValue;
                const payload = {...response, someValueFromState}
                dispatch({ type: constants.SAVE_VALUE, payload });
            });
    };
};

I had it working before when the action was not using getState() and it looked like this, where it returned Dispatch<SaveValue>:

export const saveValue = (value: number): Dispatch<SaveValue> => {
    return (dispatch: Dispatch<SaveValue>): void => {
        axios.post('www.exampleurl.com', value)
            .then((response) => {
                dispatch({ type: constants.SAVE_VALUE, response });
            });
    };
};

But once I added getState, I am not sure what to do anymore. I have tried to put the return value in a variable and can see the object I am creating is const myAttempt: (dispatch: Dispatch<SaveValue>, getState: () => State) => void but when I tried to use it as follows, it doesn't work:

export const saveValue = (value: number): (dispatch: Dispatch<SaveValue>, getState: () => StoreState) => void => {
    return (dispatch: Dispatch<SaveValue>, getState: () => State): void => {
        axios.post('www.exampleurl.com', value)
            .then((response) => {
                const someValueFromState = getState().stateValue;
                const payload = {...response, someValueFromState}
                dispatch({ type: constants.SAVE_VALUE, payload });
            });
    };
};

Doing this, I get an error: A function whose declared type is neither 'void' nor 'any' must return a value.

EDIT:

Just to add, I cannot return Dispatch<SaveValue> as I was before, otherwise I get this error: Type '(dispatch: Dispatch<SaveValue>, getState: () => State) => void' is not assignable to type 'Dispatch<SaveValue>'

Jiminez answered 11/6, 2018 at 9:6 Comment(2)
I guess you still only need export const saveValue = (value: number): Dispatch<SaveValue> => {Excrement
When I do that it says Type '(dispatch: Dispatch<SaveValue>, getState: () => State) => void' is not assignable to type 'Dispatch<SaveValue>'Jiminez
J
9

A friend helped me answer this. This was the right way to do it:

export const saveValue = (value: number): (dispatch: Dispatch<SaveValue>, getState: () => State): void => {
    return (dispatch: Dispatch<SaveValue>, getState: () => State): void => {
        axios.post('www.exampleurl.com', value)
            .then((response) => {
                const someValueFromState = getState().stateValue;
                const payload = {...response, someValueFromState}
                dispatch({ type: constants.SAVE_VALUE, payload });
            });
    };
};

The issue I was having was with my mapDispatchToProps function which was being explicitly typed and causing the error Type '(dispatch: Dispatch<SaveVisit>, getState: () => StoreState) => void' is not assignable to type 'Dispatch<SaveVisit>'. The function was:

interface MapDispatchToPropsInterface {
    saveValue : (value: number) => Dispatch<SaveValue>;
}

const mapDispatchToProps: MapDispatchToPropsInterface = {
    saveValue : ActionCreators.saveValue,
};

but the interface needed to be:

interface MapDispatchToPropsInterface {
    saveValue : (saveDetails: CheckedVisit) =>  (dispatch: Dispatch<SaveValue>, getState: () => StoreState) => void;
}
Jiminez answered 18/6, 2018 at 8:26 Comment(1)
I get a syntax error around : void => on the first line when I try this. It seems like using react-redux's built in ThunkAction is the correct approach. Relevant thread.Execrative
3
5

First configure the following in your store:

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch

then, in your function use the previously custom types

export const getUserRolUid = () => {
    return async (dispatch: AppDispatch, getState: ()=> RootState) => {

      const { uid } = getState().auth;
      const user = await loadUser(uid);
      
      if (user) {
        // update the role and send the data to redux
        dispatch(getUser(user));
      } else {
        dispatch(getUserRolUid());
      }
    };
  }
3d answered 10/6, 2022 at 21:42 Comment(2)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Maryettamaryjane
solve my problemChare

© 2022 - 2024 — McMap. All rights reserved.