day-05
Hooks
Hooks:钩子、钩住,是 React@16.8
提供的新功能。
Hooks作用: 能为函数式组件提供状态和生命周期,Hooks 只能在函数组件中使用
Hooks(提供状态和生命周期)+函数组件(展示内容)
Hooks解决了什么问题
-
组件的状态逻辑复用问题
a,在 Hooks 之前,组件的状态逻辑复用经历了:mixins(混入)、HOC(高阶组件)、render props 等模式。
b,(早已废弃)mixins 的问题:数据来源不清晰;命名冲突。
c,HOC、render props 的问题:重构组件结构,导致组件形成 JSX 嵌套地狱问题。
-
class组件自身的问题
a,选择:函数组件和 class 组件之间的区别以及使用哪种组件更合适。
b,需要理解 class 中的 this 是如何工作的。
c,同一业务的状态和业务逻辑被拆分到不同位置。
-
相比于函数组件来说,类组件不利于代码压缩和优化,也不利于TS的类型推导
# 例如不能把 componentDidMount 压缩成 c # 例如写 this 的时候没有提示,因为 this 只有在调用的时候才能确定指向,编写代码期间 TS 是不知道的
Hooks 渐进策略
目标
能够了解 Hooks 和之前 class 的写法是可以共存的。
内容
-
官方没有计划从 React 中移除 class 组件。
-
Hooks 和现有代码可以同时工作,建议渐进式地使用它们。
a,不推荐:大规模使用 Hooks 直接重构现有组件。
b,推荐:新功能用 Hooks,Hooks 实现不了的复杂功能,也可以继续用 class。
c,具体操作,从一些功能简单、非核心功能的组件开始使用 Hooks。
-
不能在 Hooks 组件中,使用 class 组件相关的 API。
a,state 与 setState。
b,钩子函数,
componentDidMount
、componentDidUpdate
、componentWillUnmount
。c,
this
相关的用法。 -
原来学习的绝大部分知识点还是要用的。
a,JSX:
{}
、onClick={handleClick}
、条件渲染、列表渲染、样式处理等。b,组件:函数组件、组件通讯。
c,React 开发理念:
单向数据流
、状态提升
等。d,解决问题的思路、技巧、常见错误的分析等。
useState 使用
作用:
为函数组件提供状态和修改状态的方法。
使用:
- 导入
useState
函数。 - 调用
useState
函数,并传入状态的初始值。 - 从
useState
函数的返回值中,拿到状态和修改状态的函数。
import React, { useState } from 'react'
export default function App() {
//参数:代表默认值
//返回值:数组[初始数据,修改数据的方法]
const [count, setCount] = useState(0)
return (
<div>
<h2>计数器:{count}</h2>
<button
onClick={() => {
setCount(count + 1)
}}
>
+1
</button>
</div>
)
}
细节
- 参数:初始状态,比如传入 0 就表示该状态的初始值为 0。
- 注意:此处的状态可以是任意值(比如,数值、字符串、对象等),注意 class 组件中的 state 必须是对象。
- 返回值:数组,数组里面包含两个值,状态和修改该状态的方法。
- 约定:修改状态的方法以 set 开头,后面跟上状态的名称。
注意事项
-
读取状态
目前,useState 只能在函数组件内部调用(也可以在后续学习的自定义 Hook 中使用),所以返回的状态也是函数内部的局部变量。
-
修改状态
a,
setCount(newValue)
是一个函数调用,参数表示新的状态值。b,调用该函数后,将使用新的状态值直接替换旧状态。
c,修改状态后,组件会自动重新渲染。
-
状态的不可变性(修改状态的时候,要使用新的状态替换掉旧的状态,而不要直接修改原状态)。
import React, { useState } from 'react'
const App = () => {
const [obj, setObj] = useState({
count: 0,
})
const handleClick = () => {
// Error
obj.count++
setObj(obj)
// Right
/* setObj({
count: obj.count + 1,
}) */
}
return (
<div>
<p>{obj.count}</p>
<button onClick={handleClick}>click</button>
</div>
)
}
export default App
useState 与组件更新过程
目标
能够说出使用功能 useState()
之后,组件的更新过程。
内容
- 组件第 1 次渲染
- 调用函数式组件,从头开始执行组件中的代码逻辑。
- 调用
useState(0)
将传入的参数作为初始状态值,即:0。 - 开始渲染组件,此时得到的状态 count 值为:0。
- 组件第 2 次渲染
- 点击按钮,调用
setCount(count + 1)
来修改状态,因为状态发生改变,所以,该组件会重新渲染。 - 组件重新渲染时,会再次执行该组件中的代码逻辑。
- 再次调用
useState(0)
,此时 React 内部会拿到最新的状态值而非初始值,比如该案例中的最新状态值为 1。 - 再次渲染组件,此时,获取到的状态 count 值为:1。
- 点击按钮,调用
- 注意:useState 的初始值(参数)只会在组件第一次渲染时生效,也就是说,以后的每次渲染,useState 获取到都是最新的状态值,React 组件内部会记住每次更新后的最新状态值!
useState 另一种写法
目标
掌握 useState(回调函数)
的写法。
内容
-
useState(回调函数)
,回调函数的返回值就是状态的初始值,该回调函数只会触发一次。
useState(() => {
return 初始值
})
-
该使用哪种形式?
a,如果状态就是需要一个普通数据(没有逻辑、无需计算),那么推荐
useState(普通的数据)
。b,如果状态是经过一些计算得到的,此时,推荐使用 useState(回调函数)。因为改回调函数只会执行一次,节省性能。
import React, { useState } from 'react'
export default function App() {
// let defaultCount = 0
// console.log(1)
// for (let i = 1; i < 10000; i++) {
// defaultCount += i
// }
// const [count, setCount] = useState(defaultCount)
console.log(1)
const [count, setCount] = useState(() => {
let defaultCount = 0
console.log(2)
for (let i = 1; i < 10000; i++) {
defaultCount += i
}
return defaultCount
})
return (
<div>
<h2>计数器:{count}</h2>
<button
onClick={() => {
setCount(count + 1)
}}
>
+1
</button>
</div>
)
}
useState 使用细则
目标
掌握如何为函数组件提供多个状态以及注意点。
内容
-
如何为函数组件提供多个状态?
多次调用 useState 即可,每一次调用返回的
[state, setState]
之间,互不影响。 -
useState 的使用细则。
a,目前,只能直接出现在函数组件中(其他 Hook 也一样)。
b,不能嵌套在 if/for/其他函数 中!(if 的条件判断、for 循环的次数、函数的调用与否都可能会影响 hook 的顺序)。
c,React 是按照 Hooks 的调用顺序来识别每一个 Hook,如果每次调用的顺序不同,导致 React 无法知道是哪一个状态和修改状态的方法。
d,可以通过开发者工具进行查看 React 对 Hook 的管理。
import React, { useState } from 'react'
export default function App() {
const [num1, setNum1] = useState(0)
const [num2, setNum2] = useState(3)
const [num3, setNum3] = useState(6)
return (
<div>
<div>
num1: {num1}
<button onClick={() => setNum1(num1 + 1)}>修改 num1</button>
</div>
<div>
num2: {num2}
<button onClick={() => setNum2(num2 + 1)}>修改 num1</button>
</div>
<div>
num3: {num3}
<button onClick={() => setNum3(num3 + 1)}>修改 num1</button>
</div>
</div>
)
}
useEffect 副作用介绍
目标
能够说出什么是副作用(side effect)。
内容
-
类比,对于 999 感冒灵来说。
a,主作用:用于治疗感冒引起的头痛,发热,鼻塞,流涕,咽痛等。
b,副作用:可见困倦、嗜睡、口渴、虚弱感。
-
那组件或一般函数的副作用是什么呢?
a,组件的副作用:对于 React 组件来说,主作用就是根据数据(state/props)渲染 UI,除此之外都是副作用,比如手动修改 DOM、数据(AJAX)请求、localStorage 操作等。
b,函数的副作用:如果一个函数修改了其局部环境之外的数据,那么它就被称为有副作用。
-
关于 useEffect。
作用:当你想要在函数组件中处理副作用(side effect),就要使用 useEffect 了。
总结
- 对于 React 组件来说,“主作用”是什么?
- 常见的有哪些“副作用”?
useEffect 基本使用
目标
能够在函数组件中操作 DOM(处理副作用)。
内容
- 执行时机:初始化时和数据变化的时候执行。
- 相当于 class 中的 componentDidMount + componentDidUpdate。
需求
在实际开发中,副作用是不可避免的。