最新公告
  • 欢迎您光临网站无忧模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 「React Build」之集成 Redux/Typescript

    正文概述 掘金(大古同学)   2021-04-07   613

    Redux 是 React 应用状态管理的一个比较流行的库!

    在本篇文章中,我们来交流下

    • 如何使用 Typescript 以强类型的方式管理 Redux 状态
    • 如何使用 React-Redux 的 Hooks 函数让 React 组件和 Redux 状态进行交互

    安装依赖

    yarn add redux react-redux
    
    yarn add @types/react-redux --dev
    
    # 安装 redux开发者工具
    $ yarn add redux-devtools --dev
    

    话说实践出真知,下面我们通过 Redux 实现一个用户名的添加和删除。以便加深我们对 Redux 的理解

    State

    我们将以下类型作为 stores 的状态类型

    // src/redux/data.d.ts
    
    // 用户的字段类型
    type Person = {
      id: number;
      name: string;
    };
    
    // 所有用户的类型
    type AppState = {
      people: Person[];
    };
    

    可以发现,我们的应用状态是一个 people ,它是包含 id/name 的数组类型

    状态我们尽量简化,因为我们主要专注于 Redux Store 以及 React 组件如何以强类型的方式进行交互。

    Actions 和 action 创建函数

    众所周知,在 Redux 中改变状态必须发起一个 action,action 中必须包含

    • 发起的动作是什么
    • 发起的动作需要传递什么东西

    在我们的例子中有两个 action

    • AddPerson:当一个用户名被添加时触发,该动作中包含了新的用户的名称
    • RemovePerson:当一个用户名被删除时触发,该动作中包含了用户的id

    接下来是 action 创建函数,它的作用是创建并返回 action 对象,下面的是我们为两个 action 实现的 action 创建函数

    // src/redux/actions/index.ts
    
    import actionTypes from "./actionTypes";
    
    export const addPerson = (personName: string) => {
      return {
        type: actionTypes.ADD_PERSON,
        payload: personName,
      } as const;
    };
    
    export const removePerson = (id: string) => {
      return {
        type: actionTypes.REMOVE_PERSON,
        payload: id,
      } as const;
    };
    

    注意,我们没有给payload 明确类型,因为 action 创建函数可以自动推断是什么类型。

    Reducer

    reducer 是一个接收 state 参数和 action,并用于更新 state 的函数,

    首先我们为 action 参数定义 Typescript 类型

    type Actions = ReturnType<typeof addPerson> | ReturnType<typeof removePerson>;
    

    这是所有 action 的联合类型。 我们使用 typeof 关键字获取 action 创建函数的类型,然后使用ReturnType获取这些函数的返回类型。 使用这种方法,我们不需要显式为 action 对象创建类型。

    reducer 函数如下所示

    import { addPerson, removePerson } from "../actions/index";
    import type { Person } from "../data.d";
    import actionTypes from "../actions/actionTypes";
    
    type Actions = ReturnType<typeof addPerson> | ReturnType<typeof removePerson>;
    
    const initialState: Person[] = [{ id: "1", name: "小萝莉" }];
    
    export default function peopleReducer(state = initialState, action: Actions) {
      switch (action.type) {
        case actionTypes.ADD_PERSON:
          return state.concat([
            {
              id: (Math.random() * 1000000).toFixed(0),
              name: action.payload,
            },
          ]);
        case actionTypes.REMOVE_PERSON:
          return state.filter((person) => person.id !== action.payload);
        default:
          break;
      }
      return state;
    }
    

    我们显式地设置了函数参数类型,且不指定返回值的类型(由 TS 的类型推断来判断)。

    「React Build」之集成 Redux/Typescript

    请注意, switch 语句中的 action.type是强类型的,因此,如果我们在case中输入错误的值,将引发报错。

    Store

    我们使用 Redux 中的 createStore 来创建一个生成 store 的函数

    import { combineReducers, createStore } from "redux";
    import { Store } from "redux";
    import { AppState } from "./data.d";
    
    import peopleReducer from "./reducers/index";
    
    const rootReducer = combineReducers<AppState>({
      people: peopleReducer,
    });
    
    function configureStore(): Store<AppState> {
      const store = createStore(rootReducer, undefined);
      return store;
    }
    
    const storeData = configureStore();
    
    export default storeData;
    

    使用 Redux 中的combinedReducers函数创建rootReducer

    store 的类型设置也很简单:使用 Redux 中的Store泛型类型,在我们的示例中为AppState

    链接组件

    终于走到组件这一步了,<( ̄ ▽  ̄)/

    首先我们需要使用 react-redux 中的 Provider 组件包裹顶层组件,然后将 store 传递到Provider组件中:

    const App = () => (
      <Provider store={store}>
        <Page />
      </Provider>
    );
    

    在子组件内部,我们可以使用 React Redux 的useSelector钩子从 store 中获取数据

    // src/pages/home/homeByFunc.tsx
    
    import React from "react";
    import { useSelector } from 'react-redux'
    
    const Index: React.FC = () => {
      .......
        const people: Person[] = useSelector((state: AppState) => state.people);
      .......
    }
    

    useSelector函数接收的参数也是一个函数,该函数从 store 获取状态并返回相关数据。 并且使用AppState类型显式设置 state 参数的类型。

    接下来,我们使用 React Redux 的useDispatch钩子来调用 action:

    // src/pages/home/homeByFunc.tsx
    
    import React from "react";
    import { useDispatch } from 'react-redux'
    
    const Index: React.FC = () => {
      .......
        const dispatch = useDispatch();
      .......
    }
    

    useDispatch返回一个我们称为dispatch的函数。 然后,我们通过将 action 创建函数传递到dispatch中来触发 action:

    // src/pages/home/homeByFunc.tsx
    const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
      e.preventDefault();
      dispatch(addPerson(newPerson));
      ...
    };
    
    const dispatchNewPerson = (id: number) => () => {
      dispatch(removePerson(id));
    };
    ...
    <button onClick={dispatchNewPerson(person.id)}>Remove</button>
    

    难道这就结束了吗??‍♂️ 不,离搭建一个完整的 React 应用有些距离。那么在下一篇文章中,我会告诉你如何在项目中实现异步Redux


    下载网 » 「React Build」之集成 Redux/Typescript

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元