WHAT - React 学习系列(六)- Managing state

Overview

As your application grows, it helps to be more intentional about how your state is organized and how the data flows between your components.

In this chapter, you'll learn how to structure your state well, how to keep your state update logic maintainable, and how to share state between distant components.

Reacting to input with state

With React, you won't modify the UI from code directly. For example, you won't write commands like "disable the button", "enable the button", "show the success message", etc. Instead, you will describe the UI you want to see for the different visual states of your component ("initial state", "typing state", "success state"), and then trigger the state changes in response to user input.

Choosing the state structure

The most important principle is that state shouldn't contain redundant or duplicated information. If there's unnecessary state, it's easy to forget to update it, and introduce bugs!

For example, this form has a redundant fullName state variable:

javascript 复制代码
  const [firstName, setFirstName] = useState('');
  const [lastName, setLastName] = useState('');
  const [fullName, setFullName] = useState('');

You can remove it and simplify the code by calculating fullName while the component is rendering:

javascript 复制代码
  const [firstName, setFirstName] = useState('');
  const [lastName, setLastName] = useState('');
  const fullName = firstName + ' ' + lastName;

This might seem like a small change, but many bugs in React apps are fixed this way.

Sharing state between components & lifting state up

Sometimes, you want the state of two components to always change together. To do it, remove state from both of them, move it to their closest common parent, and then pass it down to them via props.

This is known as "lifting state up", and it's one of the most common things you will do writing React code.

Preserving and resetting state

When you re-render a component, React needs to decide which parts of the tree to keep (and update), and which parts to discard or re-create from scratch.

By default, React preserves the parts of the tree that "match up" with the previously rendered component tree.

React lets you override the default behavior, and force a component to reset its state by passing it a different key. This tells React that if the recipient is different, it should be considered a different Chat component that needs to be re-created from scratch with the new data (and UI like inputs).

javascript 复制代码
const contacts = [
  { name: 'Taylor', email: 'taylor@mail.com' },
  { name: 'Alice', email: 'alice@mail.com' },
  { name: 'Bob', email: 'bob@mail.com' }
];
const [to, setTo] = useState(contacts[0]);

<Chat contact={to} />: Typing a message and then switching the recipient does not reset the input
<Chat key={to.email} contact={to} />: Now switching between the recipients resets the input field---even though you render the same component.

Extracting state logic into a reducer

Components with many state updates spread across many event handlers can get overwhelming.

For these cases, you can consolidate all the state update logic outside your component in a single function, called "reducer". Your event handlers become concise because they only specify the user "actions"

javascript 复制代码
function tasksReducer(tasks, action) {
  switch (action.type) {
    case 'added': {
      return [...tasks, {
        id: action.id,
        text: action.text,
        done: false
      }];
    }
    case 'changed': {
      return tasks.map(t => {
        if (t.id === action.task.id) {
          return action.task;
        } else {
          return t;
        }
      });
    }
    case 'deleted': {
      return tasks.filter(t => t.id !== action.id);
    }
    default: {
      throw Error('Unknown action: ' + action.type);
    }
  }
}
const initialTasks = [
  { id: 0, text: 'Visit Kafka Museum', done: true },
  { id: 1, text: 'Watch a puppet show', done: false },
  { id: 2, text: 'Lennon Wall pic', done: false }
];

export default function TaskApp() {
  const [tasks, dispatch] = useReducer(
    tasksReducer,
    initialTasks
  );
  function handleAddTask(text) {
    dispatch({
      type: 'added',
      id: nextId++,
      text: text,
    });
  }
  function handleChangeTask(task) {
    dispatch({
      type: 'changed',
      task: task
    });
  }
  function handleDeleteTask(taskId) {
    dispatch({
      type: 'deleted',
      id: taskId
    });
  }
}

Passing data deeply with context

Usually, you will pass information from a parent component to a child component via props. But passing props can become inconvenient if you need to pass some prop through many components, or if many components need the same information.

Context lets the parent component make some information available to any component in the tree below it---no matter how deep it is---without passing it explicitly through props.

Scaling up with reducer and context

Reducers let you consolidate a component's state update logic. Context lets you pass information deep down to other components. You can combine reducers and context together to manage state of a complex screen.

With this approach, a parent component with complex state manages it with a reducer. Other components anywhere deep in the tree can read its state via context. They can also dispatch actions to update that state.

Reacting to input with state

Choosing the state structure

Sharing state between components & lifting state up

Preserving and resetting state

Extracting state logic into a reducer

Passing data deeply with context

Scaling up with reducer and context

相关推荐
量子-Alex38 分钟前
【多模态聚类】用于无标记视频自监督学习的多模态聚类网络
学习·音视频·聚类
轻口味40 分钟前
命名空间与模块化概述
开发语言·前端·javascript
吉大一菜鸡43 分钟前
FPGA学习(基于小梅哥Xilinx FPGA)学习笔记
笔记·学习·fpga开发
前端小小王1 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发1 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
爱吃西瓜的小菜鸡3 小时前
【C语言】判断回文
c语言·学习·算法
小A1594 小时前
STM32完全学习——SPI接口的FLASH(DMA模式)
stm32·嵌入式硬件·学习
岁岁岁平安4 小时前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA4 小时前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
qq_589568104 小时前
数据可视化echarts学习笔记
学习·信息可视化·echarts