增强功能函数,可以将功能代码聚合,组件层级变浅,代码量少.
1.1、简介
在 React 的世界中,有容器组件和 UI 组件之分,在 React Hooks 出现之前,UI 组件我们可以使用函数,无状态组件来展示 UI,而对于容器组件,函数组件就显得无能为力,我们依赖于类组件来获取数据,处理数据,并向下传递参数给 UI 组件进行渲染。
React在v16.8 的版本中推出了 React Hooks 新特性,
Hook是一套工具函数的集合,它增强了函数组件的功能,
hook不等于函数组件,所有的hook函数都是以use开头。
Hooks 相比于 类组件 的 好处:
代码可读性更强,
- 原本同一块功能的代码逻辑被拆分在了不同的生命周期函数中,容易使开发者修改代码时不易查找,
通过 React Hooks 可以将功能代码聚合,方便阅读维护
组件树层级变浅,
- 在原本的代码中,我们经常使用 HOC/render/Props 等方式来复用组件的状态,增强功能等,无疑增加了组件树层数及渲染,
- 而在 React Hooks 中,这些功能都可以通过强大的自定义的 Hooks 来实现
Hooks 就是一个个小闭包!!!
1.2、使用hook限制!!!
hook只能用在函数组件中,class组件不行
普通函数不能使用hook -- 例外:普通函数名称以use开头也可以
函数组件内部的函数也不行(因为作用域不同,hook是闭包)
hook函数一定要放在函数组件的第一层,别放在if/for中(块级作用域)
要求函数组件名称必须首字母大写
1.3、常用hook函数
1.3.1、useState
保存组件状态,功能类似于类组件中的this.state状态管理
let [count, setCount] = useState(count的值 | 回调 count)
import React, { useState } from 'react'
// useState 参数值,为数组1的默认值
// 对于一些有一些需要初始计算的可以使用回调函数的方式来初始值
// let [count, setCount] = useState(() => 0)
// 固定值初始值
let [count, setCount] = useState(0)
// jsx
<button onClick={() => setCount(count + 1)}>+++</button>
因为是一个个闭包,作用域不同,所以执行几次都和其他的无关
值
回调
input事件
todolist
封装自定义hooks -- input表单
使用
1.3.2、useEffect
此函数的操作是异步的。
此hook可以模拟函数组件的生命周期,
常被别的称为:副作用处理函数。
可以调用多次
函数组件对于在一些生命周期中操作还是无能为力,所以 React提供了 useEffect 来帮助开发者处理函数组件,来帮助模拟完成一部份的开发中非常常用的生命周期方法。
useEffect 用来模拟 类组件中的3个生命周期:
componentDidMount,
componentDidUpdate,
componetWillUnMount
可以 通过 useEffect的依赖项 获取最新的数据
单个依赖 与 多个依赖
引用类型监听不到,除非地址变了
import React, { useState, useEffect } from 'react'
const App = () => {
let [count, setCount] = useState(0)
// 参数1:回调函数
// 如果没有第2个参数,表示 componentDidMount componentDidUpdate
// 如果第2个参数为空数组 表示 componentDidMount
// 如果第2个参数不空数组,只关注所写变量事件更新和挂载 componentDidMount componentDidUpdate
useEffect(() => {
if (count > 10) {
document.title = count
}
// 返回回调函数中就是 componetWillUnMount
// 在执行下一个 effect 之前,上一个 effect 就已被清除
return () => {
// 在此处,就可以把setTimout setInterval 清空
}
}, [count]);
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>+++</button>
</div>
);
}
封装自定义Hooks -- 网络请求
1
2
记得函数const没有变量提升,前后顺序很重要
3 开始封装
引用 封装的hook
1.3.3、useReducer
和ts兼容好,分散数据源,可以跨组件通信.
唯一缺少的就是无法使用 redux 提供的中间件姐就是不能实现异步,需要自定义hook
useReducer 这个 Hooks 在使用上几乎跟 Redux一模一样,
或
useReducer版todolist
修改一下自定义hook
为了能清空value
1.3.4、useContext
使用useContext可以方便我们获取Context中的数据源
1.3.5、useMemo //缓存数据
记忆组件,可以理解为计算属性 性能优化
参数2: 依赖项,
如果依赖项发生改变,重新计算
缓存计算结果的值
useMemo购物车
1.3.6、useCallback //缓存函数
记忆函数,它计算返回一个缓存函数。
修改后 ,改变count不会影响fn
父组件更新触发子组件重新渲染
只有依赖自己改变了才重新计算
顶层Api -- memo !!!!
解决--父组件更新触发子组件重新渲染
给函数组件来减少重复渲染的顶层Api,类似于PureComponent
引用
1.3.7、useRef
useRef 跟 createRef 类似,都可以用来生成对 DOM 对象的引用
useRef默认只能在html标签中使用,不可以在函数组件中使用
顶层Api -- forwardRef !!!!
让函数组件支持ref
4.3.8、useImperativeHandle 透传 高级
使用它可以透传 Ref,
因为函数组件没有实例,所以在默认自定义函数组件中不能使用ref属性,
使用为了解决此问题,react提供了一个hook和一个高阶组件完帮助函数组件能够使用ref属性。
1.3.10、react-redux-hook
react-redux支持了hook的解决方案,提供两个方法,很方便我们在项目去使用
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
const MyRedux = () => {
const { username, password } = useSelector(state => state.userinfo)
const dispatch = useDispatch()
return (
<div>
<h3>{username}</h3>
<hr />
<button onClick={
e => {
dispatch({
type: 'setname',
name: 'aaaaa'
})
}
}>修改一下姓名</button>
</div>
)
}
现在可以直接在调试工具查看了
拆出去
1.3.11、react-router-dom-hook
react-router-dom也提供了hook的解决方案
非路由直接渲染的组件 必用 hook (替代高阶组件的)
非路由直接渲染的组件可以通过
父传子
高阶组件 //弊端: 会让父子变成子孙
useHistory
获取数据
import {useLocation,useParams} from 'react-router-dom'