首页与我联系

「React Hooks 学习笔记」关于useReducer 的使用介绍(七)

By 前端达人
Published in 4-React
October 14, 2022
1 min read
「React Hooks 学习笔记」关于useReducer 的使用介绍(七)

「React Hooks 学习笔记」关于useReducer 的使用介绍(七)

React Hook 系列文章

  1. State Hook 的使用介绍(一)
  2. useEffect Hook 的使用介绍(二)
  3. React.memo 的使用介绍(三)
  4. useMemo 和 useCallback 的使用介绍(四)
  5. useRef 的使用介绍(五)
  6. useContext 的使用介绍(六)

本篇文章内容

  1. 什么是 useReducer ?
  2. 通过实例理解 useReducer
  3. useReducer 的使用总结

什么是 useReducer

首先我们来聊聊什么是 useReducer ?官方文档是这么解释的:

An alternative to useState. Accepts a reducer of type (state, action) => newState, and returns the current state paired with a dispatch method. (If you’re familiar with Redux, you already know how this works.)

1_tISLR7uiLX_IFEI8lZcgZg.png

进阶版的 useState

useState 其实和 useReducer 很相似,只不过 useReducer 是一个升级版,两者同样都是用来存储和更新数据局状态,但是 useReducer 能处理更复杂的逻辑,以下是使用两种用法达到同样效果的例子。

useState

1_-xnIIUzxJGhzDk6iubgWFw.png

useReducer

1_PftKSTKuhHO0WDIK82b6OA.png

概念跟 Redux 80% 相似

学过 Redux 的可以很轻松上手,核心的概念和思想是一模一样的:Action、Reducer、Store。

Redux 示意图:

1_5cb7j2SeIMy-Hd4tAFLmZw.png

useReducer 示意图

1_F3pXTxQAaW4QZDyDmFTeuw.jpg

接下来我们看一个简单的代码示意,点击按钮计数器+1,看完这个我们看看是如何使用的:

const { useState, useReducer } = React;

const ACTIONS = {
  INCREMENT: 'increament',
  DECREMENT: 'decreament'
}

function reducer(state, action) {
  switch(action.type) {
    case ACTIONS.INCREMENT:
      return { count: state.count + 1}
     case ACTIONS.DECREMENT:
      return { count: state.count - 1}
    default:
      return state
  }

}

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, {count: 256})

  const increase = () => { dispatch({type: ACTIONS.INCREMENT}) };
  const decrease = () => {dispatch({type: ACTIONS.DECREMENT }) };
 
  return (
    <div>
      <button onClick={decrease} />
      <span>{state.count}</span>
      <button onClick={increase} />
    </div>
  )
};

从上述代码我们可以看出 useReducer 的基础用法

  • 语法:(state, action) => newState
  • Immutable:每次都返回一个newState
  • Action:一个常规的Action对象通常有type和payload(可选)组成
    • type: 本次操作的类型,也是 reducer 条件判断的依据
    • payload: 提供操作附带的数据信息

通过实例理解 useReducer

接下来我们通过一个实例来深入学习理解下 useReducer,示例效果如下图所示:

userdemo.gif

接下来我们来分析这个简单示例的需求:

  • 一个输入框和一个提交按钮
  • 点击输入框,添加添加录入人员信息
  • 录入成功提示“人员添加成功”
  • 如果输入框不输入内容,点击添加,提示”请输入人员信息“,提示信息自动消失
  • 添加成功的人员信息以列表的形式显示在最下方
  • 每一行人员信息,对应一个删除按钮,点击后,删除对应的人员信息。

定义 Modal 提示层组件

首先我们从最简单的组件开始,定义一个 Modal 的提示层,用来对用户的输入信息进行反馈,比如“人员添加成功”,“请输入人员信”。此组件有两个属性 modalContent(提示文字)和 closeModal(关闭弹出层事件),Modal.js 文件如下:

import React, { useEffect } from 'react';

const Modal = ({ modalContent, closeModal }) => {
  useEffect(() => {
    setTimeout(() => {
      closeModal();
    }, 3000);
  });
  return (
    <div className='modal'>
      <p>{modalContent}</p>
    </div>
  );
};

export default Modal;

定义 Index 页面组件

定义 Index 组件,包含了 输入框和提示按钮,初始化数据状态 defaultState,包含三个对象属性:people(用户数据) 、isModalOpen (用于是否显示提示信息)、modalContent(提示信息内容)、同时定义了很关键的 useReducer通过不同的 type 类型进行数据的添加和删除人员信息,相关的示例代码如下:

import React, { useState, useReducer } from 'react';
import Modal from './Modal';
import { reducer } from './reducer';
const defaultState = {
  people: [],
  isModalOpen: false,
  modalContent: '',
};
const Index = () => {
  const [name, setName] = useState('');
  const [state, dispatch] = useReducer(reducer, defaultState);
  const handleSubmit = (e) => {
    e.preventDefault();
    if (name) {
      const newItem = { id: new Date().getTime().toString(), name };
      dispatch({ type: 'ADD_ITEM', payload: newItem });
      setName('');
    } else {
      dispatch({ type: 'NO_VALUE' });
    }
  };
  const closeModal = () => {
    dispatch({ type: 'CLOSE_MODAL' });
  };
  return (
    <>
      {state.isModalOpen && (
        <Modal closeModal={closeModal} modalContent={state.modalContent} />
      )}
      <form onSubmit={handleSubmit} className='form'>
        <div>
          <input
            type='text'
            value={name}
            onChange={(e) => setName(e.target.value)}
          />
        </div>
        <button type='submit'>添加</button>
      </form>
      {state.people.map((person) => {
        return (
          <div key={person.id} className='item'>
            <h4>{person.name}</h4>
            <button
              onClick={() =>
                dispatch({ type: 'REMOVE_ITEM', payload: person.id })
              }
            >
              删除
            </button>
          </div>
        );
      })}
    </>
  );
};

export default Index;

定义 useReducer 操作

useReducer 文件是核心部分,在这里我们定义相关的核心操作,例如添加、删除等操作,示例代码如下:

export const reducer = (state, action) => {
  if (action.type === 'ADD_ITEM') {
    const newPeople = [...state.people, action.payload];
    return {
      ...state,
      people: newPeople,
      isModalOpen: true,
      modalContent: '人员添加成功',
    };
  }
  if (action.type === 'NO_VALUE') {
    return { ...state, isModalOpen: true, modalContent: '请输入人员信息' };
  }
  if (action.type === 'CLOSE_MODAL') {
    return { ...state, isModalOpen: false };
  }
  if (action.type === 'REMOVE_ITEM') {
    const newPeople = state.people.filter(
      (person) => person.id !== action.payload
    );
    return { ...state, people: newPeople };
  }
  throw new Error('没有匹配的操作');
};

到这里关于本案例就介绍完了,关于 useReducer 是不是很容易理解呢。

useReducer 的使用总结

关于 useReducer 的使用总结就介绍到这里,实际上有许多情况直接用 useState 会比要建一个 useReducer 更简单,因为 useReducer 的使用方法是希望我们用像redux 的方式来管理状态,透过 action -> reducer -> store 的方式管理状态流。你应该不会想在一个简单的component 写一堆reducer 的代码,不然后续维护时你会后悔死。但是有些情况 useReducer 会比 useState 更好用,会写出更容易维护的程式码,在一些复杂的业务逻辑场景,建议使用 useReducer 。有句题外话,React 的官方网站也提到 useReducer 是 useState 的一种替代性写法,让我们以为它们是不同的东西,但是谁知道 useState 的底层其实是用 useReducer 做的呢😜。

前端达人公众号.jpg

注:本文属于原创文章,版权属于「前端达人」公众号及 qianduandaren.com 所有,未经授权,谢绝一切形式的转载


Tags

reacthook
Previous Article
「React Hooks 学习笔记」关于 useContext 的使用介绍(六)
前端达人

前端达人

专注前端知识分享

Table Of Contents

1
「React Hooks 学习笔记」关于useReducer 的使用介绍(七)
2
React Hook 系列文章
3
本篇文章内容
4
什么是 useReducer ?
5
通过实例理解 useReducer
6
useReducer 的使用总结

相关文章

「React Hooks 学习笔记」关于Custom Hooks 的使用介绍(八)
October 28, 2022
1 min

前端站点

VUE官网React官网TypeScript官网

公众号:前端达人

前端达人公众号