我应该如何输入 React 的调度函数才能像 Promise 一样执行 "then" 方法
How should I type React's dispatch function to be able to do a "then" method like a Promise
我有一个简单的应用程序,它在第一次加载时分派一个操作来填充商店。我希望能够在 dispatch
上 运行 一个 then
方法,但是打字稿对此有抱怨。
(根据 redux 的文档,调度操作的 return 值是 return value of the action itself)
中可用的代码
// 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>;
}
商店配置
我使用 @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>;
您可以创建一个承诺,然后您可以像这样使用 .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;
希望你看起来像这样。
dispatch
会 return 无论你采取什么行动 (thunk) returns.
好像是部分
({
type: "GET_TODOS",
payload: axios.get("https://jsonplaceholder.typicode.com/todos")
})
可能是错误的:你想要的可能是
const getTodos = (): ThunkAction => (dispatch) =>
axios.get("https://jsonplaceholder.typicode.com/todos").then(todos => {
dispatch({type: "GET_TODOS", payload: todos});
return todos;
});
通过这种方式,你们都可以触发您的操作,并且您的 Promise return从带有待办事项有效负载的 dispatch 中编辑。
您可能还想根据 https://redux.js.org/usage/usage-with-typescript#type-checking-redux-thunks
使用泛型键入您的 ThunkAction
好的,我自己想出来了。
问题是 useAppDispatch
.
的输入不正确
所以在 store.ts
而不是
export const useAppDispatch = () => useDispatch<AppDispatch>();
我们应该
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>();
然后在 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
});
最后,在我们应用的任何地方使用 dispatch:
dispatch(getTodos()).then((todos) => console.log(todos));
我有一个简单的应用程序,它在第一次加载时分派一个操作来填充商店。我希望能够在 dispatch
上 运行 一个 then
方法,但是打字稿对此有抱怨。
(根据 redux 的文档,调度操作的 return 值是 return value of the action itself)
中可用的代码// 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>;
}
商店配置
我使用 @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>;
您可以创建一个承诺,然后您可以像这样使用 .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;
希望你看起来像这样。
dispatch
会 return 无论你采取什么行动 (thunk) returns.
好像是部分
({
type: "GET_TODOS",
payload: axios.get("https://jsonplaceholder.typicode.com/todos")
})
可能是错误的:你想要的可能是
const getTodos = (): ThunkAction => (dispatch) =>
axios.get("https://jsonplaceholder.typicode.com/todos").then(todos => {
dispatch({type: "GET_TODOS", payload: todos});
return todos;
});
通过这种方式,你们都可以触发您的操作,并且您的 Promise return从带有待办事项有效负载的 dispatch 中编辑。
您可能还想根据 https://redux.js.org/usage/usage-with-typescript#type-checking-redux-thunks
使用泛型键入您的 ThunkAction好的,我自己想出来了。
问题是 useAppDispatch
.
所以在 store.ts
而不是
export const useAppDispatch = () => useDispatch<AppDispatch>();
我们应该
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>();
然后在 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
});
最后,在我们应用的任何地方使用 dispatch:
dispatch(getTodos()).then((todos) => console.log(todos));