“日月不肯迟,四时相催迫。”在这个属于奋斗者的新时代,人人都有追梦的权利,人人也都是梦想的筑造者。
今日学习内容
1、https://www.youtube.com/watch?v=EVFZazcxAbo&t=4112s
今日笔记
React-Hooks设计动机与工作模式(上):
函数组件与类组件的对比:
- 类组件需要继承class,函数组件不需要
- 类组件可以访问生命周期方法,函数组件不能
- 类组件可以获取到实例化后的this,并基于这个this做各种各样的事情,而函数组件不可以
- 类组件可以定义并维护state,而函数组件不可以
函数组件会捕获render内部的状态,这是两类组件最大的不同。
useState(): 为函数组件引入状态
引入状态:早期的函数组件相比于类组件,其一大劣势是缺乏定义和维护state的能力,useState正是这样一个能够为函数组件引入状态的API。
useEffect(): 允许函数组件执行副作用操作
useEffect则在一定程度上弥补了生命周期的缺席
useEffect能够为函数组件引入副作用 完成类组件中放在componentDidMount、componentDidUpdate、componentWillUnmount三个生命周期里来做的事
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import React,{ useState, useEffect } from 'react';
function IncreasingTodoList(){ const [count, setCount] = useState(0);
useEffect(()=>{ const todoList = document.getElementById("todoList"); const newItem = document.createElement("li"); newItem.innerHTML = `我是第${count}个待办项`; todoList.append(newItem); })
return( <div> <p>当前共计{count}个todo item</p> <ul id="todoList"></ul> <button onClick={ ()=>setCount(count+1) }></button> </div> ) }
|
useEffect(callBack, [])
每一次渲染后都执行的副作用:传入回调函数,不传依赖数组
useEffect(callBack)
仅在挂载阶段执行一次的副作用:传入回调函数,且这个函数的返回值不是一个函数,同时传入一个空数组
useEffect(()=>{
// 这是业务逻辑
},[])
在挂载阶段和卸载阶段执行的副作用:传入回调函数,且这个函数的返回值是一个函数,同时传入一个空数组
useEffect(()=>{
<!-- 返回一个函数B -->
return()=>{
}
}.[])
useEffect 回调中返回的函数被称为“清除函数”
这个规律不会受第二个参数或者其他因素的影响只要你在useEffect 回调中返回了一个函数它就会被作为清除函数来处理
每一次渲染都触发,且卸载阶段也会被触发的副作用:
传入回调函数,且这个函数的返回值是一个函数,同时不传第二个参数
useEffect(()=>{
})
Hooks不能放在条件语句中
若不保证hooks的执行顺序:
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
| import React, { useState } from 'react';
function PersonalInfoComponent(){ let name,age,career,setName,setAge,setCareer;
[name, setName] = useState('张三'); [age, setAge] = useState(18); [career, setCareer] = useState('前端工程师'); console.log("🚀 ~ PersonalInfoComponent ~ career:", career)
return( <div className="personalInfo"> <p>姓名: {name}</p> <p>年龄: {age}</p> <p>职业: {career}</p> <button onClick={()=>{ setName('李四'); }}>修改姓名</button> </div> ) } export default PersonalInfoComponent;
|
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
| import React, { useState } from 'react';
let isMounted = false;
function PersonalInfoComponent(){ let name,age,career,setName,setAge,setCareer;
console.log('isMounted is', isMounted);
if(!isMounted) { [name, setName] = useState('修言'); [age, setAge] = useState(20); isMounted = true; }
[career, setCareer] = useState('前端工程师'); console.log("🚀 ~ PersonalInfoComponent ~ career:", career)
return( <div className="personalInfo"> { name ? <p>姓名: {name}</p> : null} { age ? <p>年龄: {age}</p> : null} <p>职业: {career}</p> <button onClick={()=>{ setName('李四'); }}>修改姓名</button> </div> ) } export default PersonalInfoComponent;
|
以useState为例,分析React-Hooks的调用链路:
React链路在首次渲染和更新不同

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
| function mountState(initialState){ var hook = mountWorkInProgressHook();
if(typeof initialState === 'function'){ initialState = initialState(); }
const queue = hook.queue = { last: null, dispatch: null, lastRenderedReducer: basicStateReducer, lastRenderedState: initialState };
hook.memoizedState = hook.baseState = initialState;
var dispatch = queue.dispatch = dispatchAction.bind( null, currentlyrenderingFiber$1, queue ); return [hook.memoizedState, dispatch]; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function mountWorkInProgressHook(){ const hook = { memoizedState: null, baseState: null, baseQueue: null, queue: null, next: null };
if(workInProgressHook === null){ firstWorkInProgressHook = workInProgressHook = hook; }else{ workInProgressHook = workInProgressHook.next = hook; }
return workInProgressHook; }
|
更新hook调用链表:

updateState: 按顺序去遍历之前构建好的链表取出对应的数据信息进行渲染
mountState(首次渲染)构建链表并渲染
updateState依次遍历链表并渲染
hooks的渲染是通过依次遍历来定位每个hooks内容的。如果前后两次读到的链表在顺序上出现差异,那么渲染的结果自然是不可控的。
hooks的本质是链表
站在底层视角,重现PersonalInfoComponent组件的执行过程:
1 2 3
| [name, setName] = useState('张三'); [age, setAge] = useState(18); [career, setCareer] = useState('前端工程师');
|

更新后只有career的useState:

虚拟DOM -> Diff算法 -> Fiber架构