使用 React useReducer Hook

使用 React useReducer Hook

Flying
2020-02-10 / 0 评论 / 97 阅读 / 正在检测是否收录...

介绍

useReducer Hook 是 React 提供的一个 Hook,它接收一个 reducer 函数和初始 state,返回当前的 state 以及一个 dispatch 方法,可以用来更新 state。它可以用来替代 class 组件中的 statesetState 方法,使得代码更加简洁,更容易维护。

语法

useReducer Hook接受两个参数。

useReducer(<reducer>,<initialState>)

reducer 函数包含您的自定义状态逻辑,initialState 可以是一个简单的值,但通常会包含一个对象。

useReducer Hook 返回当前状态和 dispatch 方法。

示例

这是一个使用 useReducer 在待办事项应用中的示例:

  • TodoList.js
import { useState } from 'react';

export default function TaskList({
  todos,
  onChangeTodo,
  onDeleteTodo
}) {
  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>
          <Task
            todo={todo}
            onChange={onChangeTodo}
            onDelete={onDeleteTodo}
          />
        </li>
      ))}
    </ul>
  );
}

function Task({ todo, onChange, onDelete }) {
  const [isEditing, setIsEditing] = useState(false);
  let todoContent;
  if (isEditing) {
    todoContent = (
      <>
        <input
          value={todo.title}
          onChange={e => {
            onChange({
              ...todo,
              title: e.target.value
            });
          }} />
        <button onClick={() => setIsEditing(false)}>
          保存
        </button>
      </>
    );
  } else {
    todoContent = (
      <>
        {todo.title}
        <button onClick={() => setIsEditing(true)}>
          编辑
        </button>
      </>
    );
  }
  return (
    <label>
      <input
        type="checkbox"
        checked={todo.done}
        onChange={e => {
          onChange({
            ...todo,
            done: e.target.checked
          });
        }}

      />
      {todoContent}
      <button onClick={() => onDelete(todo.id)}>
        删除
      </button>
    </label>
  );
}

上述代码很简单,其中:

  1. TaskList 组件是一个函数组件,它接收一个 todos 数组,以及 onChangeTodoonDeleteTodo 函数作为参数。
  2. TaskList 组件使用todos数组渲染一个 ul 元素,其中每个 todo 都会被渲染为一个 Task 组件。
  3. Task 组件是一个函数组件,它接收一个 todo 对象,以及 onChangeonDelete 函数作为参数。
  4. Task 组件使用 todo 对象渲染一个 label 元素,其中包含一个 checkbox,用于更改 todo 的状态,以及“删除”按钮,用于删除todo。
  • AddTodo.js
import { useState } from 'react';

export default function AddTodo({ onAddTodo }) {
  const [title, setTitle] = useState('');
  return (
    <>
      <input
        placeholder="添加待办事项"
        value={title}
        onChange={e => setTitle(e.target.value)}
      />
      <button onClick={() => {
        setTitle('');
        onAddTodo(title);
      }}>添加</button>
    </>
  )
}

上述代码主要做了三件事情:

  1. 我们使用 useState Hook 来创建一个 title 状态,并使用 setTitle 函数来更新它。
  2. 渲染一个输入,它的值是 title 状态,并且当用户输入时,它会调用setTitle函数来更新 title 状态。
  3. 渲染 “添加” 按钮,当用户点击时,它会调用 onAddTodo 函数,并将 title 状态作为参数传递给它,然后将 title 状态重置为空字符串。
  • index.js
import { useReducer } from 'react';
import AddTodo from './AddTodo';
import TodoList from './TodoList';

const initialTodos = [
  { id: 0, title: 'Buy milk', done: true },
  { id: 1, title: 'Eat tacos', done: false },
  { id: 2, title: 'Brew tea', done: false },
];

let nextId = 3;

function App() {
  const [todos, dispatch] = useReducer(
    todoReducer,
    initialTodos
  );

  function handleAddTodo(title) {
    dispatch({
      type: 'added',
      id: nextId++,
      title: title,
    });
  }

  function handleChangeTodo(todo) {
    dispatch({
      type: 'changed',
      todo: todo
    });
  }

  function handleDeleteTodo(taskId) {
    dispatch({
      type: 'deleted',
      id: taskId
    });
  }

  return (
    <>
      <AddTodo
        onAddTodo={handleAddTodo}
      />
      <TodoList
        todos={todos}
        onChangeTodo={handleChangeTodo}
        onDeleteTodo={handleDeleteTodo}
      />
    </>
  );
}

function todoReducer(todos, action) {
  switch (action.type) {
    case 'added': {
      return [...todos, {
        id: action.id,
        title: action.title,
        done: false
      }];
    }
    case 'changed': {
      return todos.map(t => {
        if (t.id === action.todo.id) {
          return action.todo;
        } else {
          return t;
        }
      });
    }
    case 'deleted': {
      return todos.filter(t => t.id !== action.id);
    }
    default: {
      throw Error('Unknown action: ' + action.type);
    }
  }
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Todos />);
  1. todoReducer 函数接收两个参数:todosactiontodos 是一个数组,包含所有的 todo 项,action 是一个对象,包含要执行的操作的类型和其他可能需要的数据。
  2. 根据 action.type的值,todoReducer 函数会执行不同的操作:
  3. 如果 action.type 的值为 added,则会添加一个新的 todo 项到 todos 数组中;
  4. 如果 action.type 的值为 changed,则会更新 todos 数组中指定的 todo 项;
  5. 如果 action.type 的值为 deleted,则会从 todos 数组中删除指定的 todo 项。
  6. 最后,todoReducer函数会返回一个新的todos数组,其中包含所有的更新后的todo项。

useReducer Hook 是在React应用程序中管理状态的一个很好的方法。它比 useState Hook 更强大,允许更复杂的状态逻辑。

1

评论 (0)

取消