From 4ce097435687257d57369042429ab71f28d946b6 Mon Sep 17 00:00:00 2001 From: rikako <496063163@qq.com> Date: Mon, 29 May 2023 23:58:51 +0800 Subject: [PATCH] =?UTF-8?q?react=E6=96=87=E6=A1=A3=E9=98=85=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react/react文档.md | 141 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/react/react文档.md b/react/react文档.md index 4b54345..ca0eb21 100644 --- a/react/react文档.md +++ b/react/react文档.md @@ -373,6 +373,147 @@ function handleNameChange(e) { ## 更新state数组 和object一样,在react中数组应该也要是不可变的,在更新state中的值时,也应该再创建一个新的数组,并用新的数组值设置 +## 重新渲染时组件状态的保存 +只要一个组件还在**UI树中相同的位置**,那么react就会保存其state;如果组件被移除,或另有一个类型的组件被渲染在相同的位置,那么react将会丢弃旧组件的state。 +如果不同同类型组件被渲染在相同位置,state仍然会被保存。 + +### 在UI树结构的同一位置渲染不同组件 +如果在两次渲染之间,在UI树的同一位置渲染了相同类型的组件,那么默认情况下两次ui组件的state相同的。 +如果要显式指定两次渲染的组件是不同的,各自有独立的state,可以为两次渲染的组件指定不同的key: +```js +import { useState } from 'react'; + +export default function Scoreboard() { + const [isPlayerA, setIsPlayerA] = useState(true); + return ( +
+ {isPlayerA ? ( + + ) : ( + + )} + +
+ ); +} + +function Counter({ person }) { + const [score, setScore] = useState(0); + const [hover, setHover] = useState(false); + + let className = 'counter'; + if (hover) { + className += ' hover'; + } + + return ( +
setHover(true)} + onPointerLeave={() => setHover(false)} + > +

{person} 的分数:{score}

+ +
+ ); +} + +``` +> 注意,key并不需要全局唯一,key只用于指定父组件内部的顺序 + +### 前后两次组件渲染位于不同UI树位置 +如果前后两次组件渲染时位于不同的ui树位置,如果要保持前后两次渲染组件state相同,可以为前后两次渲染指定相同的key,那么在前后两次渲染时,即使ui树位置不同,state仍然会延续相同。 + +state和树中位置相关,例如 +```js +// 第一次渲染 +return ( + +) +// 第二次渲染 +return ( + +) +``` +在上述两次渲染中,`item a`和`item b`父节点`
  • `的顺序虽然发生了改变,但是能够通过`
  • `元素的key属性来区分,故而`item a`和`item b`的state仍然会保持原样。显示效果为列表第一行元素和第二行元素发生了对调。 + +## Reducer +reducer是一个函数,接受两个参数: +- 当前state +- action,代表改变状态的参动作,数据结构可以自定义 + +reducer方法的返回值是一个新的state,react会将旧的状态设置为新的状态。 + +### Reducer使用 +```js +import { useReducer } from 'react'; + +// 用于替换useState +// useReducer接受两个参数,一个reducer函数,一个state的初始值 +// 其会返回有状态的值和一个dispatch函数,dispatch函数用于分发action给reducer +const [tasks, dispatch] = useReducer(tasksReducer, initialTasks); + +// 之后可以向dispatch函数提交action +function handleAddTask(text) { + dispatch({ + type: 'added', + id: nextId++, + text: text, + }); + } + +function handleChangeTask(task) { + dispatch({ + type: 'changed', + task: task, + }); + } + +// reducer函数会处理action +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('未知 action: ' + action.type); + } + } +} +``` + +