避免为 Redux 中的每个操作声明接口的可重用方法?
Reusable way to avoid declaring an Interface for every action in Redux?
我最近开始使用 TypeScript 来使用 React/Redux (-Saga) 对我的项目进行编码,但有些事情困扰着我。
正如您在下面的代码中所看到的,为每个操作声明一个接口看起来不错,因为文件中没有太多内容,但随着时间的推移,如果操作更多,这可能看起来不太好(例如 edit/delete ),尤其是类型声明。
actions/articles.ts
import { IArticle, IStoreAction } from '../../../interfaces';
import { createAction } from './createAction';
export enum ActionTypes {
createArticleRequested = 'articles/createArticleRequested',
createArticleSucceeded = 'articles/createArticleSucceeded',
createArticleFailed = 'articles/createArticleFailed',
}
interface ICreateArticleRequestAction {
type: ActionTypes.createArticleRequested,
article: IArticle;
}
interface ICreateArticleFailureAction {
type: ActionTypes.createArticleFailed,
error: string;
}
interface ICreateArticleSuccessAction {
type: ActionTypes.createArticleSucceeded,
article: IArticle;
}
export type ArticlesAction =
ICreateArticleRequestAction |
ICreateArticleSuccessAction |
ICreateArticleFailureAction;
export const createArticleRequest = (article: IArticle)
: IStoreAction<typeof article> => createAction(
ActionTypes.createArticleRequested,
article
);
export const createArticleSuccess = (article: IArticle)
: IStoreAction<typeof article> => createAction(
ActionTypes.createArticleSucceeded,
article
);
export const createArticleFailure = (error: string)
: IStoreAction<typeof error> => createAction(
ActionTypes.createArticleFailed,
error
);
我试图开发一个可以基于单个界面的可重用解决方案,但它通常会带来一系列错误。是否有更好的现有设置来使整个事情更清洁、更可重用?
感谢您的关注!
是的,使用官方的 Redux 工具包,这是当今(自 2019 年以来)编写的任何 Redux 代码的官方推荐。
参见Why Redux Toolkit is How To Use Redux Today。
它使所有那些动作类型接口完全过时(我们甚至 consider it an antipattern 构建那些动作联合类型)并且还取消了 switch..case reducers,ACTION_TYPES,hand-written action creators,不可变的 reducer 逻辑,createStore/applyMiddleware。此外,现代 Redux 不使用 connect/mapStateToProps.
它将您的代码减少到 hand-written 遗留 Redux 代码的大约 25%。
我建议通过 official Redux Essentials Tutorial 从头开始启动 Redux Toolkit。
@phry 是我的 Redux 工具包 co-maintainer,为了继续他所说的,使用 TS 编写 Redux reducer 文件的正确方法如下所示(根据我们的 TypeScript Quick Start 页面) :
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import type { RootState } from '../../app/store'
// Define a type for the slice state
interface CounterState {
value: number
}
// Define the initial state using that type
const initialState: CounterState = {
value: 0
}
export const counterSlice = createSlice({
name: 'counter',
// `createSlice` will infer the state type from the `initialState` argument
initialState,
reducers: {
increment: state => {
state.value += 1
},
decrement: state => {
state.value -= 1
},
// Use the PayloadAction type to declare the contents of `action.payload`
incrementByAmount: (state, action: PayloadAction<number>) => {
state.value += action.payload
}
}
})
export const { increment, decrement, incrementByAmount } = counterSlice.actions
// Other code such as selectors can use the imported `RootState` type
export const selectCount = (state: RootState) => state.counter.value
export default counterSlice.reducer
请注意,您所需要的只是切片缩减器状态的类型,以及每个 case 缩减器的 action: PayloadAction<SomePayloadTypeHere>
。
事实上,we specifically advise against trying to write TS union types for actions。
我最近开始使用 TypeScript 来使用 React/Redux (-Saga) 对我的项目进行编码,但有些事情困扰着我。
正如您在下面的代码中所看到的,为每个操作声明一个接口看起来不错,因为文件中没有太多内容,但随着时间的推移,如果操作更多,这可能看起来不太好(例如 edit/delete ),尤其是类型声明。
actions/articles.ts
import { IArticle, IStoreAction } from '../../../interfaces';
import { createAction } from './createAction';
export enum ActionTypes {
createArticleRequested = 'articles/createArticleRequested',
createArticleSucceeded = 'articles/createArticleSucceeded',
createArticleFailed = 'articles/createArticleFailed',
}
interface ICreateArticleRequestAction {
type: ActionTypes.createArticleRequested,
article: IArticle;
}
interface ICreateArticleFailureAction {
type: ActionTypes.createArticleFailed,
error: string;
}
interface ICreateArticleSuccessAction {
type: ActionTypes.createArticleSucceeded,
article: IArticle;
}
export type ArticlesAction =
ICreateArticleRequestAction |
ICreateArticleSuccessAction |
ICreateArticleFailureAction;
export const createArticleRequest = (article: IArticle)
: IStoreAction<typeof article> => createAction(
ActionTypes.createArticleRequested,
article
);
export const createArticleSuccess = (article: IArticle)
: IStoreAction<typeof article> => createAction(
ActionTypes.createArticleSucceeded,
article
);
export const createArticleFailure = (error: string)
: IStoreAction<typeof error> => createAction(
ActionTypes.createArticleFailed,
error
);
我试图开发一个可以基于单个界面的可重用解决方案,但它通常会带来一系列错误。是否有更好的现有设置来使整个事情更清洁、更可重用?
感谢您的关注!
是的,使用官方的 Redux 工具包,这是当今(自 2019 年以来)编写的任何 Redux 代码的官方推荐。
参见Why Redux Toolkit is How To Use Redux Today。
它使所有那些动作类型接口完全过时(我们甚至 consider it an antipattern 构建那些动作联合类型)并且还取消了 switch..case reducers,ACTION_TYPES,hand-written action creators,不可变的 reducer 逻辑,createStore/applyMiddleware。此外,现代 Redux 不使用 connect/mapStateToProps.
它将您的代码减少到 hand-written 遗留 Redux 代码的大约 25%。
我建议通过 official Redux Essentials Tutorial 从头开始启动 Redux Toolkit。
@phry 是我的 Redux 工具包 co-maintainer,为了继续他所说的,使用 TS 编写 Redux reducer 文件的正确方法如下所示(根据我们的 TypeScript Quick Start 页面) :
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import type { RootState } from '../../app/store'
// Define a type for the slice state
interface CounterState {
value: number
}
// Define the initial state using that type
const initialState: CounterState = {
value: 0
}
export const counterSlice = createSlice({
name: 'counter',
// `createSlice` will infer the state type from the `initialState` argument
initialState,
reducers: {
increment: state => {
state.value += 1
},
decrement: state => {
state.value -= 1
},
// Use the PayloadAction type to declare the contents of `action.payload`
incrementByAmount: (state, action: PayloadAction<number>) => {
state.value += action.payload
}
}
})
export const { increment, decrement, incrementByAmount } = counterSlice.actions
// Other code such as selectors can use the imported `RootState` type
export const selectCount = (state: RootState) => state.counter.value
export default counterSlice.reducer
请注意,您所需要的只是切片缩减器状态的类型,以及每个 case 缩减器的 action: PayloadAction<SomePayloadTypeHere>
。
事实上,we specifically advise against trying to write TS union types for actions。