react文档阅读
This commit is contained in:
141
react/react文档.md
141
react/react文档.md
@@ -373,6 +373,147 @@ function handleNameChange(e) {
|
|||||||
## 更新state数组
|
## 更新state数组
|
||||||
和object一样,在react中数组应该也要是不可变的,在更新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 (
|
||||||
|
<div>
|
||||||
|
{isPlayerA ? (
|
||||||
|
<Counter person="Taylor" />
|
||||||
|
) : (
|
||||||
|
<Counter person="Sarah" />
|
||||||
|
)}
|
||||||
|
<button onClick={() => {
|
||||||
|
setIsPlayerA(!isPlayerA);
|
||||||
|
}}>
|
||||||
|
下一位玩家!
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Counter({ person }) {
|
||||||
|
const [score, setScore] = useState(0);
|
||||||
|
const [hover, setHover] = useState(false);
|
||||||
|
|
||||||
|
let className = 'counter';
|
||||||
|
if (hover) {
|
||||||
|
className += ' hover';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={className}
|
||||||
|
onPointerEnter={() => setHover(true)}
|
||||||
|
onPointerLeave={() => setHover(false)}
|
||||||
|
>
|
||||||
|
<h1>{person} 的分数:{score}</h1>
|
||||||
|
<button onClick={() => setScore(score + 1)}>
|
||||||
|
加一
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
> 注意,key并不需要全局唯一,key只用于指定父组件内部的顺序
|
||||||
|
|
||||||
|
### 前后两次组件渲染位于不同UI树位置
|
||||||
|
如果前后两次组件渲染时位于不同的ui树位置,如果要保持前后两次渲染组件state相同,可以为前后两次渲染指定相同的key,那么在前后两次渲染时,即使ui树位置不同,state仍然会延续相同。
|
||||||
|
|
||||||
|
state和树中位置相关,例如
|
||||||
|
```js
|
||||||
|
// 第一次渲染
|
||||||
|
return (
|
||||||
|
<ul>
|
||||||
|
<li key={id1}><Item key="a" /></li>
|
||||||
|
<li key={id2}><Item key="b"/></li>
|
||||||
|
</ul>
|
||||||
|
)
|
||||||
|
// 第二次渲染
|
||||||
|
return (
|
||||||
|
<ul>
|
||||||
|
<li key={id2}><Item key="b"/></li>
|
||||||
|
<li key={id1}><Item key="a"/></li>
|
||||||
|
</ul>
|
||||||
|
)
|
||||||
|
```
|
||||||
|
在上述两次渲染中,`item a`和`item b`父节点`<li>`的顺序虽然发生了改变,但是能够通过`<li>`元素的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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user