React.memo()、useCallback()、useMemo()区别及基本使用
来源 | https://www.fly63.com/
// Parent.jsx
import 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.jsx
import React from 'react';
function Child() {
console.log('------------子組件重新渲染');
return (
<div style={{ background: 'pink', margin: '50px 0' }}>
<button type="button">子組件</button>
</div>
);
}
export default Child;
// Child.jsx
import React from 'react';
// ...other code
export default React.memo(Child);
React.memo(Comp[, fn])
用于减少子组件的渲染
React.memo 是一个高阶组件(参数为组件,返回的是新组件的函数即为高阶组件)
对外部来说,React.memo 会检查道具的变更,只有当核心的道具发生变化时组件才会重新成型,纽扣我们再点击父组件,子就不会膨胀了。
React.memo 对复杂对象做浅层对比,可以通过过程第二个参数来控制对比
第二个参数为一个增强渲染细节的函数。
function MyComponent(props) {
/* 使用 props 渲染 */
}
function areEqual(prevProps, nextProps) {
/*
如果把 nextProps 传入 render 方法的返回结果与
将 prevProps 传入 render 方法的返回结果一致则返回 true,
否则返回 false
*/
}
export default React.memo(MyComponent, areEqual);
useMemo(fn[, DependentArray])
// Parent.jsx
import React, { useState, useMemo } from 'react';
import Child from '../Child';
function Parent() {
const [parentCount, setParentCount] = useState(0);
const [otherCount, setOtherCount] = useState(0);
console.log('父組件重新渲染--------------');
// 一个复杂的计算
const computedFn = (a, b) => {
console.log('----重新执行了计算----');
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.jsx
import 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.jsx
import React from 'react';
function Child(props) {
const { computedValue, computedFn } = props;
console.log('------------子組件重新渲染');
return (
<div style={{ background: 'pink', margin: '50px 0' }}>
<div>
父组件传入的计算结果:
{computedValue}
</div>
<button type="button" onClick={computedFn}>子組件</button>
</div>
);
}
export default React.memo(Child);
// Parent.jsx
import React, { useState, useCallback } from 'react';
// ...other code
const computedFn = useCallback(() => {
console.log(parentCount);
return parentCount + 1;
}, [parentCount]) ;
// ...other code
export 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 对象在组件的整个生命周期内保持不变
// 从 ref 读取它,current的变更不会引起组件的重新渲染,而函数内部又能拿到正确的值
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 被初始化为粒子的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变
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>
</>
);
}
学习更多技能
请点击下方公众号
评论