本系列将讲述 React Hooks 的使用方法,从 useState 开始,将包含以下内容:css
掌握 React Hooks api 将更好的帮助你在工做中使用,对 React 的掌握更上一层楼。本系列将使用大量实例代码和效果展现,很是易于初学者和复习使用。react
上一章,咱们学习了 useCallback 来进行性能优化,关于性能优化还有另外一个 hook api,那就是 useMemo,下面咱们一块儿经过一个例子来看看。api
依然是计数器示例,建立2个计数器,并能区分当前是奇数或者偶数,为了模拟点击按钮时包含大量的计算逻辑影响性能,在判断偶数的方法中添加了没有用的计算逻辑,为了让性能差的明显。代码以下数组
Counter.tsx缓存
import React, { useState } from 'react'
function Counter() {
const [counterOne, setCounterOne] = useState(0)
const [counterTwo, setCounterTwo] = useState(0)
const incrementOne = () => {
setCounterOne(counterOne + 1)
}
const incrementTwo = () => {
setCounterTwo(counterTwo + 1)
}
const isEven = () => {
let i = 0
while (i < 1000000000) i += 1
return counterOne % 2 === 0
}
return (
<div> <button onClick={incrementOne} >Count One = {counterOne}</button> <span> { isEven() ? 'even' : 'odd' } </span> <br /> <button onClick={incrementTwo} >Count Two = {counterTwo}</button> </div>
)
}
export default Counter
复制代码
App.tsx性能优化
import React from 'react'
import './App.css'
import Counter from './components/27.Counter'
const App = () => {
return (
<div className="App"> <Counter /> </div>
)
}
export default App
复制代码
页面展现以下函数
咱们发现点击第一个按钮有较长的延迟,由于咱们的判断偶数的逻辑中包含了大量的计算逻辑。可是,咱们点击第二个按钮,也有较长的延迟!这很奇怪。性能
这是由于,每次 state 更新时,组件会 rerender,isEven 会被执行,这就是咱们点击第二个按钮时,也会卡的缘由。咱们须要优化,告诉 React 不要有没必要要的计算,特别是这种计算量复杂的。学习
在咱们的示例中,咱们要告诉 React,在点击第二个按钮时,不要执行 isEven 方法。这时就须要 useMemo hook 登场了。优化
与 useCallback 的用法相似。
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
复制代码
返回一个 memoized 值。 把“建立”函数和依赖项数组做为参数传入
useMemo
,它仅会在某个依赖项改变时才从新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。记住,传入
useMemo
的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操做,诸如反作用这类的操做属于useEffect
的适用范畴,而不是useMemo
。若是没有提供依赖项数组,
useMemo
在每次渲染时都会计算新的值。你能够把 useMemo 做为性能优化的手段,但不要把它当成语义上的保证。 未来,React 可能会选择“遗忘”之前的一些 memoized 值,并在下次渲染时从新计算它们,好比为离屏组件释放内存。先编写在没有 useMemo 的状况下也能够执行的代码 —— 以后再在你的代码中添加 useMemo,以达到优化性能的目的。
首先引入 useMemo
import React, { useState, useMemo } from 'react'
复制代码
而后将 isEven 方法使用 useMemo 改写,返回值赋给 isEven
const isEven = useMemo(() => {
let i = 0
while (i < 1000000000) i += 1
return counterOne % 2 === 0
}, [counterOne])
复制代码
最后记得修改 isEven 使用的地方,已经从一个方法变为了一个变量
{
isEven ? 'even' : 'odd'
}
复制代码
完整代码以下
Counter.tsx
import React, { useState, useMemo } from 'react'
function Counter() {
const [counterOne, setCounterOne] = useState(0)
const [counterTwo, setCounterTwo] = useState(0)
const incrementOne = () => {
setCounterOne(counterOne + 1)
}
const incrementTwo = () => {
setCounterTwo(counterTwo + 1)
}
const isEven = useMemo(() => {
let i = 0
while (i < 1000000000) i += 1
return counterOne % 2 === 0
}, [counterOne])
return (
<div> <button onClick={incrementOne} >Count One = {counterOne}</button> <span> { isEven ? 'even' : 'odd' } </span> <br /> <button onClick={incrementTwo} >Count Two = {counterTwo}</button> </div>
)
}
export default Counter
复制代码
效果以下
咱们看到点击第二个按钮时,不会有任何卡顿,这是由于使用了 useMemo 只依赖了 counterOne 变量,点击第二个按钮时,isEven 读取的是缓存值,不须要再从新计算是否为偶数。
useCallback 是缓存了函数自身,而 useMemo 是缓存了函数的返回值。
本章经过示例展现了 useMemo 在性能优化中的做用。经过缓存函数的返回值,避免没必要要的调用,从而避免了组件 rerender。
最后有分析了 useMemo 与 useCallback 的区别,即 useMemo 是缓存了函数的返回值,useCallback 是缓存了函数自身。这两个 api 都是性能优化的方法。