React.memo()、useCallback()、useMemo()區(qū)別及基本使用

來源 | https://www.fly63.com/
// Parent.jsximport react, { useState } from 'react';import Child from '../Child';function Parent() {const [parentCount, setParentCount] = useState(0);console.log('父組件重新渲染--------------');return (<div style={{ background: 'lightseagreen' }}><Child /><button type="button" onClick={() => { setParentCount(parentCount + 1); }}>父組件 +1</button></div>);}export default Parent;
// Child.jsximport React from 'react';function Child() {console.log('------------子組件重新渲染');return (<div style={{ background: 'pink', margin: '50px 0' }}><button type="button">子組件</button></div>);}export default Child;
// Child.jsximport React from 'react';// ...other codeexport default React.memo(Child);
React.memo(Comp[, fn])
用于減少子組件的渲染
React.memo 是一個高階組件(參數(shù)為組件,返回的是新組件的函數(shù)即為高階組件)
對外部來說,React.memo 會檢查道具的變更,只有當(dāng)核心的道具發(fā)生變化時組件才會重新成型,紐扣我們再點擊父組件,子就不會膨脹了。
React.memo 對復(fù)雜對象做淺層對比,可以通過過程第二個參數(shù)來控制對比
第二個參數(shù)為一個增強渲染細(xì)節(jié)的函數(shù)。
function MyComponent(props) {/* 使用 props 渲染 */}function areEqual(prevProps, nextProps) {/*如果把 nextProps 傳入 render 方法的返回結(jié)果與將 prevProps 傳入 render 方法的返回結(jié)果一致則返回 true,否則返回 false*/}export default React.memo(MyComponent, areEqual);
useMemo(fn[, DependentArray])
// Parent.jsximport React, { useState, useMemo } from 'react';import Child from '../Child';function Parent() {const [parentCount, setParentCount] = useState(0);const [otherCount, setOtherCount] = useState(0);console.log('父組件重新渲染--------------');// 一個復(fù)雜的計算const computedFn = (a, b) => {console.log('----重新執(zhí)行了計算----');return a + b;};const computedValue = useMemo(() => {return computedFn(parentCount, 1);}, [parentCount]);return (<div style={{ background: 'lightseagreen' }}><Child parentCount={parentCount} computedValue={computedValue} /><button type="button" onClick={() => { setParentCount(parentCount + 1); }}>父組件 +1</button><button type="button" onClick={() => { setOtherCount(otherCount + 1); }}>父組件 otherCount+1</button></div>);}
useCallback(fn[, DependentArray])
// Parent.jsximport React, { useState } from 'react';import Child from '../Child';function Parent() {const [parentCount, setParentCount] = useState(0);const [otherCount, setOtherCount] = useState(0);console.log('父組件重新渲染--------------');const computedFn = () => {return parentCount + 1;};return (<div style={{ background: 'lightseagreen' }}><Child parentCount={parentCount} computedFn={computedFn} /><button type="button" onClick={() => { setParentCount(parentCount + 1); }}>父組件 +1</button><button type="button" onClick={() => { setOtherCount(otherCount + 1); }}>父組件 otherCount+1</button></div>);}export default Parent;// Child.jsximport React from 'react';function Child(props) {const { computedValue, computedFn } = props;console.log('------------子組件重新渲染');return (<div style={{ background: 'pink', margin: '50px 0' }}><div>父組件傳入的計算結(jié)果:{computedValue}</div><button type="button" onClick={computedFn}>子組件</button></div>);}export default React.memo(Child);
// Parent.jsximport React, { useState, useCallback } from 'react';// ...other codeconst computedFn = useCallback(() => {console.log(parentCount);return parentCount + 1;}, [parentCount]) ;// ...other codeexport default Parent;
import React, { useState, useCallback } from 'react';import Child from '../Child';let a = 0;function Parent() {const [parentCount, setParentCount] = useState(0);const [otherCount, setOtherCount] = useState(0);console.log('父組件重新渲染--------------');const computedFn = useCallback(() => {// 依賴項為空,這里的打印值始終不變;// 因為組件state變化時會重新渲染整個組件,而這里parentCount取的始終是第一次渲染版本的值console.log(parentCount);// 這里的打印值會實時更新,因為變量直接定義在組件外部,不受組件重新渲染影響console.log(a);return parentCount + 1;}, []) ;return (<div style={{ background: 'lightseagreen' }}><Child parentCount={parentCount} computedFn={computedFn} /><button type="button" onClick={() => { setParentCount(parentCount + 1); a += 1; }}>父組件 +1</button><button type="button" onClick={() => { setOtherCount(otherCount + 1); }}>父組件 otherCount+1</button></div>);}export default Parent;
function Form() {const [text, updateText] = useState('');const textRef = useRef();useEffect(() => {textRef.current = text; // 把它寫入 ref});const handleSubmit = useCallback(() => {// ref 對象在組件的整個生命周期內(nèi)保持不變// 從 ref 讀取它,current的變更不會引起組件的重新渲染,而函數(shù)內(nèi)部又能拿到正確的值const currentText = textRef.current;alert(currentText);}, [textRef]);return (<><input value={text} onChange={e => updateText(e.target.value)} /><ExpensiveTree onSubmit={handleSubmit} /></>);}
使用引用
看看官方介紹
const refContainer = useRef(initialValue);
useRef 返回一個附屬的 ref 對象,其 .current 被初始化為粒子的參數(shù)(initialValue)。返回的 ref 對象在組件的整個生命周期內(nèi)保持不變
function TextInputWithFocusButton() {const inputEl = useRef(null);const onButtonClick = () => {// `current` 指向已掛載到 DOM 上的文本輸入元素inputEl.current.focus();};return (<><input ref={inputEl} type="text" /><button onClick={onButtonClick}>Focus the input</button></>);}
學(xué)習(xí)更多技能
請點擊下方公眾號
![]()

評論
圖片
表情
