使用TypeScript处理Redux

介绍

以简洁方式解释Redux是什么,以及TypeScript和Redux结合的优点。

这篇文章介绍了如何让 TypeScript 初学者能够使用 Redux。内容类似于备忘录,如果时间紧急,请参考原视频。

参考来源:使用TypeScript的React Redux Toolkit。

创建的资料

 

Redux 是什么?

Redux是一个JavaScript状态管理库,可以帮助我们以可预测的方式集中管理应用程序的状态并进行操作。

若不使用Redux来处理数据,就需要在React应用程序中使用中继方式将数据从一个组件传递到另一个组件。

TypeScript 和 Redux 的组合的好处

通过使用TypeScript确保类型安全,并使用Redux统一管理应用程序的状态,可以使数据的更改可预测,容易定位错误,并且易于调试。此外,Redux将应用程序逻辑分离开来,提高了代码的可读性。

前提知識

要阅读此文章,需要使用Redux来使用数据,并且需要有TypeScript的基础知识。

另外,在开发过程中我们会使用VSCode。请确保您的电脑上事先安装了Node.js。

Redux的基础

Redux 的基本概念解釋

Redux通过统一管理应用程序的状态。
Redux的要素和相关图如下所示。

    • Action

 

    • ActionCreator

 

    • Store

 

    • State

 

    Reducer
redux.png

关于state(状态)、action(行动)和reducer(减速器)

在Redux中,它是用于存储应用程序状态的数据。它是不可变的,并在整个应用中共享。

行动

通过事件或数据来表示对象,并发出更改状态的请求。它具有类型和数据。

减速器

这是一个简单的函数,接收一个动作并改变状态。会根据前一个状态和动作生成一个新的状态。

不可变数据是什么?

Redux 保留的数据是不可更改的,它指的是无法进行更改的数据。为了更新数据,需要使用 Action。

使用Redux Toolkit的方式

Redux Toolkit 是什么?

Redux Toolkit是Redux官方的库,旨在简化Redux开发,支持不可变数据更新、自动生成代码以及调试功能。

项目设置

使用 Create React App 工具来初始化一个 React 项目。

创建一个名为「redux-ts」的目录,并使用Create React App来设置React项目。

前提条件是指在进行某项工作或达到某一目标之前必须满足的条件。

    • Node.js と npm (Node Package Manager) がインストールされていること。

 

    Visual Studio Code (VS Code) がインストールされていること。

步骤

打开终端,创建一个名为”redux-ts”的文件夹,并切换到该文件夹。使用下面的命令进行切换:

mkdir redux-ts
cd redux-ts

如果没有在全局安装Create React App,请使用以下命令进行安装。

npm install -g create-react-app

3:使用Create React App工具来设置新的React项目。执行以下命令。

npx create-react-app ./

通过这个方法,将在”redux-ts”中创建一个新项目。

创建React项目后,使用以下命令打开VS Code。

code .

在VS Code中,可以打开”redux-ts”目录并编辑React应用程序。

将Redux Toolkit集成到项目中

请在命令行中进入项目的根目录,并安装所需的库。然后执行以下命令。

npm i react-redux @reduxjs/toolkit

目录结构

请按照以下方式构建目录结构并建立示例。

src
├components
│├Add.tsx
│└List.tsx
├store
│├features
││└personSlice.ts
│└store.ts
├App.tsx
└index.tsx

src/components/Add.tsx:
src/components/Add.tsx:

用於用戶添加新元素的組件。其中包括輸入新數據的欄位和”添加”按鈕。使用useAddDispatch更新數據。

import React, { useRef, MouseEvent } from 'react';
import { useAddDispatch } from '../store/store';
import { addPerson } from '../store/features/personSlice';

const Add = () => {
  const name = useRef<string>('');
  const age = useRef<number>(0);
  const dispatch = useAddDispatch();
  const handleSubmit = (e: MouseEvent<HTMLButtonElement>) => {
    e.preventDefault();
    // age.currentが空の時、0を代入する
    if (!age.current) {
      age.current = 0;
    }
    dispatch(addPerson({ name: name.current, age: age.current }));
  };
  return (
    <form>
      <div>
        <label htmlFor="">Person Name:</label>
        <input onChange={(e) => (name.current = e.target.value)} />
      </div>
      <div>
        <label htmlFor="">Person Age:</label>
        <input
          type="number"
          placeholder="年齢"
          pattern="^[0-9]+$"
          onChange={(e) => (age.current = parseInt(e.target.value))}
        />
      </div>
      <button onClick={handleSubmit}>追加</button>
    </form>
  );
};

export default Add;

src/components/List.tsx: src/components/List.tsx:

用于显示数据列表的组件。使用Redux的状态通过useAppSelector来获取数据,并以列表形式显示。

import React from 'react';
import { useAppSelector } from '../store/store';

const List = () => {
  const persons = useAppSelector((state) => state.person.persons);
  return (
    <div>
      <p>This is List Components</p>
      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Age</th>
          </tr>
        </thead>
        <tbody>
          {persons.map((person) => (
            <tr key={person.id}>
              <td>{person.id}</td>
              <td>{person.name}</td>
              <td>{person.age}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

export default List;

src/store/features/personSlice.ts:
src/store/features/personSlice.ts文件:

使用Redux Toolkit定义切片。此文件包含切片的名称、初始状态、操作创建者和减速器。

import { createSlice, PayloadAction } from '@reduxjs/toolkit';

export interface Person {
  id: number;
  name: string;
  age: number;
}

interface PersonState {
  persons: Person[];
}

const initialState: PersonState = {
  persons: [],
};

export const PersonSlice = createSlice({
  name: 'person',
  initialState,
  reducers: {
    addPerson: (
      state,
      action: PayloadAction<{ name: string; age: number }>
    ) => {
      state.persons.push({
        id: state.persons.length,
        name: action.payload.name,
        age: action.payload.age,
      });
    },
  },
});
export default PersonSlice.reducer;
export const { addPerson } = PersonSlice.actions;

src/store/store.ts:

Assuming the sentence is referring to a file or location in a computer program, here is one possible way to paraphrase the sentence in Chinese:

源代码/商店/store.ts:

在中文中,我們要設置 Redux store並創建根 reducer。使用 useDispatch 和 useSelector 來選取並使用正確的類型。

import { configureStore } from '@reduxjs/toolkit';
import { PersonSlice } from './features/personSlice';
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';

export const store = configureStore({
  reducer: {
    person: PersonSlice.reducer,
  },
});
//useDispatch は typeof store.dispatch の型を使用しています。
// これにより、Reduxストアの dispatch 関数の型が正確に推論され、
// アクションをディスパッチする際に適切な型チェックが行われます。
// これにより、タイポやアクションの誤用を防ぎ、コードの安全性を確保します。
export const useAddDispatch: () => typeof store.dispatch = useDispatch;
//useSelector は TypedUseSelectorHook<ReturnType<typeof store.getState>> の
// 型を使用しています。これにより、Reduxストアの状態に関する型情報が提供され、
// コンポーネント内で状態を選択する際に型安全性が確保されます。
// 正確な型情報が提供されることで、状態の型が一致しない場合に発生するエラーを回避できます。
export const useAppSelector: TypedUseSelectorHook<
  ReturnType<typeof store.getState>
> = useSelector;

src/App.tsx文件中:

应用程序的入口点。它包含了一个 Add 组件和一个 List 组件,并将 Redux 存储作为提供者提供。

import './App.css';
import List from './components/List';
import Add from './components/Add';

function App() {
  return (
    <div className="App">
      <Add />
      <List />
    </div>
  );
}

export default App;

src/index.tsx:
src/index.tsx文件:

渲染应用程序的入口点。

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from 'react-redux/es/exports';
import { store } from './store/store'; // Reduxストアをインポート

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <Provider store={store}>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Provider>
);

应用程序演示

以下是示例的功能:
1:该应用程序由列表视图和添加表单构成。
2:初始状态下,列表是空的。
3:用户可以在“姓名”输入框和“年龄”输入框中输入值,然后点击“添加”按钮以添加新的姓名和年龄。
4:新的姓名和年龄将会被添加到列表中,并在列表内显示。

这次演示的主要重点是使用Redux Toolkit来管理应用程序的状态。

本次只由简单的元素构成,但如果涉及到不同的元素,可以通过创建单独的文件并进行管理,如“personSlice.ts”,使得开发变得更加容易,即使规模庞大也能处理得更加方便。

在这种情况下,总结出来的结果是什么。

通过Redux和TypeScript的组合,可以提高应用程序的开发效率,减少运行时错误和无法预测的错误风险。此外,还可以提高代码的可读性和可维护性,特别适用于大型应用程序的开发。

bannerAds