避免为 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