文章目录
1. React hooks介绍
React Hooks是用来做什么的?
对函数型组件进行增强,让函数型组件可以存储状态,可以拥有处理副作用的能力,让开发者在不适用类组件的情况下,实现相同的功能。
类组件的不足(Hooks要解决的问题)
-
缺少逻辑复用机制
为了复用逻辑增加无实际渲染效果的组件,增加了组件层级显示十分臃肿,增加了调试的难度以及运行效率的降低
-
类组件经常会变得很复杂难以维护
将一组相干的业务逻辑拆分到了多个生命周期函数中,在一个声明周期函数内存在多个不相干的业务逻辑
-
类成员方法不能保证this指向的正确性
2. React hooks使用
Hooks意思为钩子,React Hooks就是一堆钩子函数,React通过这些钩子函数对函数型组件进行增强,不同的钩子函数提供了不同的功能。
useState()
- 接收唯一的参数即状态初始值,初始值可以使任意数据类型
- 返回值为数组,数组中存储状态值和更改状态值的方法,方法名称约定以set开头,后面加上状态名称
- 方法可以被调用多次,用以保存不同状态值
- 参数可以是一个函数,函数返回什么,初始状态就是什么,函数只会被调用一次,用在初始值是动态值的情况
细节:
- 参数为函数时只会被调用一次,用在初始值是动态值的情况
- 调用set方法时也可以传递一个值或者函数,函数有一个形参就是我们的状态值,函数返回值就是我们要修改的值
- set方法本身是异步的
import React, {
useState } from 'react'
export default function Demo(props) {
// 这样写的话每次被渲染的时候都会执行没有意义的props.count
// const propsCount = props.count || 0
// 建议这样写,每次渲染的时候就只会执行一次了
const [count, setCount] = useState(() => {
return props.count || 0
})
function click () {
// setCount(count + 1)
setCount(count => {
const newCount = count + 1
// 因为异步,所以写在这里
document.title = newCount
return newCount
})
// setCount异步 拿不到最新的newCount
// document.title = newCount
}
return <div>
<span>{
count}</span>
<button onClick={
click}>+ 1</button>
</div>
}
useReducer
useReducer是另一种让函数组件保存状态的方式。
import React, {
useReducer } from 'react'
function reducer (state, action) {
switch (action.type) {
case 'increment':
return state + 1;
case 'decrement':
return state - 1;
default:
return state
}
}
export default function Demo(props) {
const [count, dispatch] = useReducer(reducer, 0)
return <div>
<span>{
count}</span>
<button onClick={
() => dispatch({
type: 'increment'})}>+ 1</button>
<button onClick={
() => dispatch({
type: 'decrement'})}>- 1</button>
</div>
}
useContext
在跨组件层级获取数据时简化获取数据的代码。
import React, {
createContext, useContext } from 'react'
const countContext = createContext()
export default function Demo(props) {
return <countContext.Provider value={
100}>
<Foo />
</countContext.Provider>
}
function Foo () {
const count = useContext(countContext)
return <div>{
count}</div>
}
// function Foo () {
// return <countContext.Consumer>
// {
// value => {
// return <div>{value}</div>
// }
// }
// </countContext.Consumer>
// }
useEffect
让函数型组件拥有处理副作用的能力,类似声明周期函数
-
useEffect执行时机,可以把useEffect看做componentDidMount,componentDidUpdate和componentWillUnmount这三个函数的组合
useEffect(() => {}) => componentDidMount,componentDidUpdate
useEffect(() => {}, []) => componentDidMount
useEffect(() => () => {}) => componentWillUnmount
-
useEffect使用方法,例如组件加载的时候添加事件,设置定时器
-
useEffect解决的问题
- 按照用途将代码进行分类(将一组相干的业务逻辑归置到了同一个副作用函数中)
- 简化重复代码,使组件内部代码更加清晰,例如将componentDidMount,componentDidUpdate的代码合并在一起了
-
只有指定数据发生变化时触发effect
useEffect(() => { document.title = count }, [count])
-
useEffect结合异步函数,useEffect中的参数函数不能是异步函数,因为useEffect函数要返回清理资源的函数,如果是异步函数就返回了promise,会报错,可以使用IIFE的方式来使用异步函数
// 使用链式调用的方式 export default function Demo() { useEffect(() => { getData().then(res => { console.log(res) }) }, []) return <div>Demo</div> } // 下面这样async await的方式会报错 // export default function Demo() { // useEffect(async () => { // const res = await getData() // console.log(res) // }, []) // return <div>Demo</div> // } // 如果需要使用异步函数,则要像下面这样使用IIFE export default function Demo() { useEffect(() => { (async function (){ const res = await getData() console.log(res) }()) }, []) return <div>Demo</div> }