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);
+ }
+ }
+}
+```
+
+