相信现在有很多写React的小伙伴喜欢hooks的简洁,从class迁移到了Hook的组件方式!
先简单回顾下hook组件的一般写法
1、 useState
用来获取和修改 组件中用到的状态
const [state, setState] = useState(initialState);
2、useEffect
用来处理组件副作用
useEffect(()=>{
...
},[...]);
赋值给 useEffect 的函数会在组件渲染到屏幕之后执行
3、 useContext
用来接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定。
const Context = React.createContext(null);
...
<Context.Provider value={appstate}>
</Context.Provider>
...
const _context = useContext(Context);
4、 useCallback
useCallback用来缓存一个函数
useCallback(fn, deps)
5、 useMemo
useMemo用来缓存一个值
useMemo(()=> (...), deps)
以上是HOOK提供的api。 用HOOK编写REACT组件是一件容易的事情。但是编写好组件确不很容易。需要正确理解React推出这些api背后真正的含义。
1、useState 的运用
函数组件没有生命周期。在我组件中我想要获取一个最新值 一个最新的远程数据该怎么做呢? useState 的 setState 方法会触发组件的重渲染。这就间接的提供了在组件的任何位置获取最新变量值的可能。
import {useState} from 'react';
export default function App() {
const [state, setState] = useState(0);
const handleclick = ()=>setState(item=>++item)
return (
<div className="App">
<h1>Hello ,{state}</h1>
<button onClick={handleclick}>click!</button>
</div>
);
}
上面的handleclick的每次执行都会调用setState,随后react就会重渲染整个组件!!! 包括里面的所有函数方法!随着组件的重新执行,自然组件内申明的所有变量最新值都会在本次运行中获得。
也就是说useState不仅仅有获取最新state的能力,他可以重渲染整个组件!
而在实际项目中可能会在一个组件中用到很多的变量和数据。自然就会用到很多的useState, 每次setState都会重渲染组件和组件的子组件,这个时候自然大家会有一种焦虑 ,这么多重渲染会不会造成性能问题,页面卡顿呢?有没有什么优化方案呢? 很多人想到了useCallback 和 useMemo。并且使用他们来缓存函数和变量。
const handleclick = useCallback(()=>setState(item=>++item),[])
问题表面上看似解决了! 如果仔细了解就会知道useCallback 和 useMemo 的第二个参数 是个依赖数组,每次运行通过浅比较,如果依赖变化 则重新执行被包裹的函数。在这个比较的过程中也是一个消耗。
性能优化不是免费的。它们总是伴随着成本,但并不总是伴随着抵消成本的收益。
useCallback \ useMemo
一般用来包装需要传递给子组件得 方法 和复杂对象 来避免不必要得 子组件重渲染
通常用在缓存 父组件 传递给子组件得 引用参数 上;这样可以弥补引用参数浅比较总是不相等,而引起得每次不必要得渲染!
除此之外,还有以下优化建议:
- 如果一个函数没有使用组件内的任何值,你应该把它提到组件外面去定义,这是最简单的反正不必要渲染的途径!
- useState这个钩子函数只在没有时候才创建,之后都是读取,不影响性能。
- effect中的依赖数组如果是个函数,可以通过useCallback(()=》{},[])方法.该方法只有在依赖改变时,才会改变引用.这样可以保持正确的依赖比较。
- 降低组件的复杂度,利用函数式思想,使组件细粒度化,减少不必要的渲染!