规则
hook只能在函数组件 || 自定义组件使用,不能在普通函数 || 类组件里使用
useState
- 它返回一个状态和一个修改状态的方法,状态需要通过这个方法来进行修改;
* 初始化有两种 useState 全都是异步 (react事件,原生 addEventListener ajax 生命周期
异步是防止重复调用相同的 修改状态 不管调用多少次都执行最后一次 调用不同的合并成一次执行
* 第一种
* const [x,setX] = useState(值)
* 第二种
* const [y, setY] = useState(()=>{
* 逻辑
* return 必须有
* return 值
* })
* 获取异步的值
* setX(preValue => {
preValue // 上一次的值
return 值
}}
}
useEffect
useEffect(() => { //挂载 组件渲染完成后执行一次 componentDidMount
console.log('我是挂载');
let timer = setInterval(() => {
}, 1000)
}, [])
useEffect(() => { // 更新 监听的依赖只要发生改变的时候就执行一次 componentDidUpdate
console.log('我是更新');
}, [x, y])
useEffect(() => { // 销毁 监听的依赖卸载的时候就执行一次 componentWillUnmount
return () => {
console.log('我是销毁');
}
}, [x, y])
useMemo (react 中的计算属性)
return 必须有 return的值 就是我们缓存的值
如果我们写的代码有很大的计算,逻辑当页面更新的时候每次都执行会浪费性能 所以用useMemo缓存值
两个参数 第一个回调函数 第二个是依赖
页面首次执行完会缓存数据 第二次直接拿缓存的值
let useMemoFn = useMemo(() => {
let num = 0
for (let index = 0; index < 100; index++) {
num += index
}
console.log('我执行了');
return num
}, [x]) x发生改变他就会执行一次
依赖发生改变会重新执行
useCallback
当子组件接收一个函数props时,一般会使用useCallback来缓存这个函数
useCallback返回的是一个 memoized(缓存)函数,
在依赖不变的情况下,多次定义的时候,返回的值是相同的,
他的实现原理是当使用一组参数初次调用函数时,会缓存参数和计算结果,
当再次使用相同的参数调用该函数时,会直接返回相应的缓存结果。
useCallBack并不能阻止函数重新创建,它只能通过依赖决定返回新的函数还是旧的函数,从而在依赖不变的情况下保证函数地址不变
useCallBack需要配合React.memo使用
React.memo通过校验Props中的数据的内存地址是否改变来决定组件是否重新渲染组件的
useMemo useCallback
useMemo和useCallback的共同点:
接收的参数都是一样的,第一个是回调函数,第二个是依赖的数据
它们都是当依赖的数据发生变化时才会重新计算结果,起到了缓存作用
useMemo和useCallback的区别:
useMemo计算结果是return回来的值,通常用于缓存计算结果的值
useCallback计算结果是一个函数,通常用于缓存函数
mome
React.Memo 只能用于函数组件
在只有父组件的某一个状态改变,父组件下面所有的子组件不论是否使用了该状态,都会进行重新渲染
这个函数可以检测从父组件接收的props,并且在父组件改变state的时候对比这个state是否是本组件在使用,如果不是,则拒绝重新渲染。
用来缓存组件的渲染,避免不必要的更新,也是一个高阶组件
如果子组件没有用React.memo进行包裹的话,父组件的重新渲染就会导致子组件跟着一起重新渲染
两个参数 第一个是组件 返回新组件
第二个参数 === showComponentUpdate(自动比较)比较最新的props跟上一次的props
基础类型比较值,引用类型比较指针 我们可以用一个插件 isEqual
useRef
1.获取DOM对象
2.保存数据
const ref = useRef(可以给一个默认值), useRef 返回一个对象 这个对象的指针 不会改变,
可以获取DOM 节点 <div ref="ref" />
可以获取上一次的值
二、useRef相当于在函数式组件中添加了一个实例对象。useRef不会因为组件的更新而丢失数据,虽然组件进行了更新,但是通过useRef保存的数据并不随之发生改变。
useRef还可以对DOM元素添加事件,如:可以使用 useRef 配合 useEffect 使 input 输入框聚焦。
三、useRef和CreateRef的区别
1.createRef 每次渲染都会返回一个新的引用,而 useRef 每次都会返回相同的引用
2.ref对象的值发生改变之后,不会触发组件重新渲染。
- 返回一个可变的 ref 对象,该对象只有个 current 属性,初始值为传入的参数( initialValue )。
- 返回的 ref 对象在组件的整个生命周期内保持不变
- 当更新 current 值时并不会 re-render ,这是与 useState 不同的地方
- 更新 useRef 是 side effect (副作用),所以一般写在 useEffect 或 event handler 里
- useRef 类似于类组件的 this
useRef 不仅仅是用来管理 DOM ref 的,它还相当于 this , 可以存放任何变量.
作用
- useRef可以用来定义变量,这些变量更改之后不会引起页面重新渲染,比如分页获取数据时,存储页码。
- useRef也可以用来区分初始渲染还是更新(通过current有没值,具体见示例库里的didOrUpdate.tsx)
- 在DOM节点上定义ref属性,通过.current就可以获取到该DOM元素
- 通过forwardRef就可以给函数子组件传入ref属性。
- 使用useImperativeHandle用于定义暴露给父组件的ref方法
useContext
useContext()可以实现组件之间的共享状态(通信) , 可以实现父子之间的通信
使用useContext,无论有多少层子组件,他们都可以直接获取最上层定义的值,所以下层组件要共享状态无需通过上传组件的传输。
- 使用React的createContext方法创建一个context上下文,并将其导出
- 将需要共享状态的组件用 上下文中的Provider标签包裹
- 子组件引入context上下文并作为useContext的参数
- 取出共享值