学习如何使用react写好一个组件,然后深入学习原理 (学习神光大佬的小册做的笔记)

useEffect

effect被翻译为副作用.
纯函数是指同样的入参会得到同样的返回值。比如函数式组件,同样的props会得到同样的返回结果。
但是有了effect之后,每次执行函数,额外执行了一些逻辑,这些逻辑就是副作用。

副作用是指在函数执行过程中对外部状态的影响,或者依赖外部状态。常见的副作用包括:

修改全局变量
发起网络请求
直接操作 DOM
订阅事件
在 React 函数组件中,如果每次渲染时都执行这些操作,就会产生副作用。

在 React 函数组件中,如果每次渲染时都执行这些操作,就会产生副作用。

useEffect
React 的 useEffect Hook 用来处理副作用。它允许你在函数组件中执行副作用,比如数据获取、订阅、或者手动修改 DOM。useEffect 可以看作是函数组件中的生命周期方法。

useEffect 参数的那个函数不支持使用 async, 所以想用 async await 需要单独写一个函数或在里面写一个立即执行函数

useLayoutEffect

大部分情况下,把 useEffect 换成 useLayoutEffect 是一样的, 区别是什么呢
js执行和渲染是阻塞的

useEffect中effect的执行是异步的, 它会进入EventLoop调度执行.
所以effect执行的逻辑有两种可能

  1. 下次渲染前执行effect
  2. 下次渲染后执行effect

第2种就导致页面会出现闪动,因为第一次渲染的时候state是之前的值,渲染之后effect又改了state,会再渲染一次.

一般也没啥问题,如果不想闪动一下,就用useLayoutEffect

它和useeffect的区别是它的effect执行是同步的,也就是在同一个任务里

这样浏览器就会等effect逻辑执行完再渲染,虽然页面不闪烁了,但如果effect逻辑要执行很久就阻塞渲染了,超过50ms的任务就被称作长任务,会阻塞渲染,导致掉帧

同步、异步执行effect各有好处,所以react暴漏了这两个hook,让开发者自己决定

useReducer

useReducer 的类型参数传入 Reducer<数据的类型,action 的类型>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import { Reducer, useReducer } from "react";

interface Data {
result: number;
}

interface Action {
type: 'add' | 'minus',
num: number
}
function reducer(state: Data, action: Action) {

switch(action.type) {
case 'add':
return {
result: state.result + action.num
}
case 'minus':
return {
result: state.result - action.num
}
}
return state;
}

function App() {
const [res, dispatch] = useReducer<Reducer<Data, Action>>(reducer, { result: 0});

return (
<div>
<div onClick={() => dispatch({ type: 'add', num: 2 })}>加</div>
<div onClick={() => dispatch({ type: 'minus', num: 1 })}>减</div>
<div>{res.result}</div>
</div>
);
}

export default App;

它还有另一种重载,通过函数来创建初始数据,这时候 useReducer 第二个参数就是传给这个函数的参数。
并且在类型参数里也需要传入它的类型。

1
2
3
4
5
const [res, dispatch] = useReducer<Reducer<Data, Action>, string>(reducer, 'zero', (param) => {
return {
result: param === 'zero' ? 0 : 1
}
});