前言
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。本文是一篇以实战为主的文章,主要讲解实际项目中如何使用hooks以及一些最佳实践,不会一步步再介绍一遍react hooks的由来和基本使用,因为写hooks的文章很多,而且官网对于react hooks的介绍也很详细,所以大家不熟悉的可以看一遍官网。
你将收获
react hooks核心API使用以及注意事项
实现一个小型redux
实现自定义的useState
实现自定义的useDebounce
实现自定义的useThrottle
实现自定义useTitle
实现自定义的useUpdate
实现自定义的useScroll
实现自定义的useMouse
实现自定义的createBreakpoint
正文
1. react hooks核心API使用注意事项
笔者在项目中常用的hooks主要有useState, useEffect,useCallback,useMemo,useRef。当然像useReducer, useContext, createContext这些钩子在H5游戏中也会使用,因为不需要维护错综复杂的状态,所以我们完全可以由上述三个api构建一个自己的小型redux(后面会介绍如何实现小型的redux)来处理全局状态,但是对于企业复杂项目来说,我们使用redux及其生态会更加高效一些。
我们在使用hooks和函数组件编写我们的组件时,第一个要考虑的就是渲染性能,我们知道如果在不做任何处理时,我们在函数组件中使用setState都会导致组件内部重新渲染,一个比较典型的场景:
当我们在容器组件手动更新了任何state时,容器内部的各个子组件都会重新渲染,为了避免这种情况出现,我们一般都会使用memo将函数组件包裹,来达到class组件的pureComponent的效果:
import React, { memo, useState, useEffect } from 'react'
const A = (props) => {
console.log('A1')
useEffect(() => {
console.log('A2')
})
return <div>A</div>
}
const B = memo((props) => {
console.log('B1')
useEffect(() => {
console.log('B2')
})
return <div>B</div>
})
const Home = (props) => {
const [a, setA] = useState(0)
useEffect(() => {
console.log('start')
setA(1)
}, [])
return <div><A n={a} /><B /></div>
}
当我们将B用memo包裹后,状态a的更新将不会导致B组件重新渲染。其实仅仅优化这一点还远远不够的,比如说我们子组件用到了容器组件的某个变量或者函数,那么当容器内部的state更新之后,这些变量和函数都会重新赋值,这样就会导致即使子组件使用了memo包裹也还是会重新渲染,那么这个时候我们就需要使用useMemo和useCallback了。
useMemo可以帮我们将变量缓存起来,useCallback可以缓存回调函数,它们的第二个参数和useEffect一样,是一个依赖项数组,通过配置依赖项数组来决定是否更新。
import React, { memo, useState, useEffect, useMemo } from 'react'
const Home = (props) => {
const [a, setA] = useState(0)
const [b, setB] = useState(0)
useEffect(() => {
setA(1)
}, [])
const add = useCallback(() => {
console.log('b', b)
}, [b])
const name = useMemo(() =>