- Published on
描述UI和添加交互
- Authors

- Name
- 李丹秋
笔记
Thinking in React
Step1: 按照层级结构,划分页面
- 程序角度:遵守单一职责原则,一个组件只做一件事情。
- CSS角度:考虑css选择器的结构
- 设计角度:考虑如何组织设计层级
Step2: 尽可能创建静态容器
自顶向下的去创建容器,底层组件应该只需要作为UI渲染组件,避免拥有自己的状态。
Step3: 找到UI状态的最小但完整的表示
- 如果一个组件的所有数据都来自于props,则不是有状态组件
- 如果一个数据会被频繁修改且不能通过其他有状态数据合成得到,则是有状态数据
- 如果每次渲染数据都需要保持不变,则不是有状态组件
Step4: 识别State应该存放在那里
- 识别哪些组件需要有状态
- 寻找这些组件的公共父节元素
- 决定状态应该存放在那里
Step4: 添加逆向数据流
为你的组件添加可以触发父级状态改变的函数。
事件交互
事件冒泡
export default function Toolbar() {
return (
<div className="Toolbar" onClick={() => {
alert('You clicked on the toolbar!');
}}>
<button onClick={() => alert('Playing!')}>
Play Movie
</button>
<button onClick={() => alert('Uploading!')}>
Upload Image
</button>
</div>
);
}
默认会执行事件冒泡,执行子元素click事件后,会继续出发父元素click事件, 可以添加e.stopPropagation来阻止冒泡
组件内存
import { useState } from 'react';
import { sculptureList } from './data.js';
export default function Gallery() {
const [index, setIndex] = useState(0);
function handleClick() {
setIndex(index + 1);
}
let sculpture = sculptureList[index];
return (
<>
<button onClick={handleClick}>
Next
</button>
<h2>
<i>{sculpture.name} </i>
by {sculpture.artist}
</h2>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<img
src={sculpture.url}
alt={sculpture.alt}
/>
<p>
{sculpture.description}
</p>
</>
);
}
这里通过useState,使得index具备State,每次修改都会重新渲染页面,注意sculpture并没有使用useState,每次重新渲染,都会根据index获取最新的值,这也符合上面提到的能够通过现有state生成的数据,无需变成state
组件每一次重新渲染,useState都会返回两个值,第一个是被存储的state variable, 第二个是state setter function。当第二次渲染的时候,虽然执行的是初始值,但是react记得之前改变后的值。
Reader and Commit
- 触发渲染,分为首次渲染后再次渲染
- diff 算法
- appendChild
- Broswer Render
State as a Snapshot
当我们去更新state的时候,才会执行渲染。 当React重新渲染组件的时候,会执行以下操作
- React 再一次执行函数组件
- 函数组件返回一个新的jsx快照,函数执行过程中所有的props、事件、本地变量,都是用的当前渲染时候的state值被计算出来的。
- React更新视图去匹配函数执行的结果
import { useState } from 'react';
export default function Form() {
const [to, setTo] = useState('Alice');
const [message, setMessage] = useState('Hello');
function handleSubmit(e) {
e.preventDefault();
setTimeout(() => {
alert(`You said ${message} to ${to}`);
}, 5000);
}
return (
<form onSubmit={handleSubmit}>
<label>
To:{' '}
<select
value={to}
onChange={e => setTo(e.target.value)}>
<option value="Alice">Alice</option>
<option value="Bob">Bob</option>
</select>
</label>
<textarea
placeholder="Message"
value={message}
onChange={e => setMessage(e.target.value)}
/>
<button type="submit">Send</button>
</form>
);
}
以上示例,当我点击了发送之后,然后再改变下拉框的值,弹出的结果还是点击那一瞬间的值。
Queueing a Seriew of State Updates
React只有当事件函数执行完成之后,才会触发渲染,但是多个事件函数之间的独立的,会独立执行多次渲染。
setNumber(number + 5);
setNumber(n => n + 1);
setNumber(42);
| queued update | n | returns |
|---|---|---|
| replace with 5 | 0 (unused) | 5 |
| n => n + 1 | 5 | 5 + 1 = 6 |
| “replace with 42” | 6 (unused) | 42 |
Update Objects/Array in State
建议使用immer这个三方库去存储对象