[英]How should I type React's dispatch function to be able to do a "then" method like a Promise
I have a simple app which dispatches an action on first load to populate the store.我有一个简单的应用程序,它在第一次加载时分派一个操作来填充商店。 I want to be able to run a
then
method on dispatch
but typescript complains about this.我希望能够在
dispatch
时运行then
方法,但 typescript 对此表示抱怨。
(According to redux's documentation, the return value of dispatching an action is the return value of the action itself ) (根据redux的文档,dispatch action的返回值是action本身的返回值)
Code available in Codesandbox代码在Codesandbox中可用
// app.jsx
function App() {
const dispatch = useAppDispatch();
useEffect(() => {
dispatch(getTodos()).then((todos) => console.log(todos));
// ^^^^^
// Property 'then' does not exist on type '{ type: "GET_TODOS"; payload: Promise<AxiosResponse<Todo[], any>>; }'.
}, []);
return <div className="App">Hello World!</div>;
}
I use @reduxjs/toolkit
to configure my store and have a redux-promise-middleware
set up for it so that upon "fulfillment" of my promised-based actions an <ACTION>_FULFILLED
action will also be dispatched.我使用
@reduxjs/toolkit
来配置我的商店,并为其设置了一个redux-promise-middleware
,以便在“完成”我基于承诺的操作时,还将分派一个<ACTION>_FULFILLED
操作。
// store.ts
import { configureStore } from '@reduxjs/toolkit';
import promiseMiddleware from 'redux-promise-middleware';
import rootReducer from './reducer';
import { useDispatch } from 'react-redux';
const store = configureStore({
reducer: rootReducer,
middleware: [promiseMiddleware],
});
export type RootState = ReturnType<typeof rootReducer>;
export type AppDispatch = typeof store.dispatch;
export const useAppDispatch = () => useDispatch<AppDispatch>();
export default store;
// reducer.ts
import produce, { Draft } from "immer";
import { Action } from "./action";
export type Todo = {
userId: number;
id: number;
title: string;
completed: boolean;
}
interface State {
todos: Todo[];
}
const initialState: State = {
todos: []
};
const reducer = produce((draft: Draft<State>, action: Action) => {
switch (action.type) {
case "GET_TODOS_FULFILLED": {
const todos = action.payload.data;
return todos;
}
}
}, initialState);
export default reducer;
// action.ts
import axios from "axios";
import type { AxiosResponse } from "axios";
import type { Todo } from './reducer'
export const getTodos = (): {
type: "GET_TODOS";
payload: Promise<AxiosResponse<Todo[]>>;
} => ({
type: "GET_TODOS",
payload: axios.get("https://jsonplaceholder.typicode.com/todos")
});
export type Action = ReturnType<typeof getTodos>;
You can create a promise and then you can use.then like this.你可以创建一个 promise 然后你可以像这样使用.then。
import { useEffect } from "react";
import { getTodos } from "./action";
import { useAppDispatch } from "./store";
function App() {
const dispatch = useAppDispatch();
const myPromise = ()=>Promise.resolve(dispatch(getTodos())); /// creating promise
useEffect(() => {
myPromise().then((res:any)=>{
console.log(res.value.data)
})
}, []);
return <div className="App">Hello World!</div>;
}
export default App;
Hope you are looking something like this.希望你看起来像这样。
dispatch
would return whatever your action (thunk) returns. dispatch
将返回您的操作 (thunk) 返回的任何内容。
It seems the part好像是部分
({
type: "GET_TODOS",
payload: axios.get("https://jsonplaceholder.typicode.com/todos")
})
might be wrong: what you wanted is probably可能是错的:你想要的可能是
const getTodos = (): ThunkAction => (dispatch) =>
axios.get("https://jsonplaceholder.typicode.com/todos").then(todos => {
dispatch({type: "GET_TODOS", payload: todos});
return todos;
});
This way you both have your action fired and your Promise returned from dispatch with todos payload.这样你们两个都可以触发你的动作,你的 Promise 从带有待办事项负载的调度中返回。
You may also want to type your ThunkAction with generics according to https://redux.js.org/usage/usage-with-typescript#type-checking-redux-thunks您可能还想根据https://redux.js.org/usage/usage-with-typescript#type-checking-redux-thunks 使用 generics 键入您的 ThunkAction
Ok I figured it out by myself.好的,我自己想出来了。 The problem was the incorrect typing of
useAppDispatch
.问题是
useAppDispatch
的输入不正确。
So in store.ts
instead of having所以在
store.ts
而不是
export const useAppDispatch = () => useDispatch<AppDispatch>();
We should have我们本应该
import type { ThunkAction, ThunkDispatch } from "redux-thunk";
export type AppThunk<RT = void> = ThunkAction<
Promise<RT>,
RootState,
unknown,
AnyAction
>;
export type AppThunkDispatch = ThunkDispatch<RootState, void, Action>;
export const useAppDispatch = () => useDispatch<AppThunkDispatch>();
And then in action.ts
we could write our thunk
actions like this:然后在
action.ts
中我们可以这样写我们的thunk
动作:
export const getTodos =
(): AppThunk<{ type: "SET_TODOS"; payload: Todo[] }> => (dispatch) =>
axios
.get<Todo[]>("https://jsonplaceholder.typicode.com/todos")
.then((response) => response.data)
.then((todos) => dispatch(setTodos(todos)));
export const setTodos = (
todos: Todo[]
): {
type: "SET_TODOS";
payload: Todo[];
} => ({
type: "SET_TODOS",
payload: todos
});
And lastly for using dispatch anywhere in our app:最后,在我们应用程序的任何地方使用 dispatch:
dispatch(getTodos()).then((todos) => console.log(todos));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.