useMemo和memo区别是什么?
- React.memo 是一个高阶组件,它用于避免函数组件进行不必要的重新渲染。 简单来说, useMemo 是用于优化计算操作,而 React.memo 是用于优化渲染。
- useMemo 是一个 Hook,它用于避免执行昂贵的计算操作。当依赖项改变时, useMemo 将重新计算缓存的值。
- 如果依赖的数据经常变化,就不用useMemo
- 如果依赖的数据偶尔变化,就可以用useMemo
问题: 每次修改n1, getN3 就会执行一次
js
const Test = function () {
const [n1, setN1] = useState(0)
const [n2] = useState(0)
const click = () => setN1(n1+1)
const getN3 = () => {
alert('getN2执行了')
return n2+100
}
return (
<>
<h1 onClick={click} >{n1}</h1>
<h1>{getN3()}</h1>
</>
)
};
解决: 使用useMemo
js
const Test = function () {
const [n1, setN1] = useState(0)
const [n2] = useState(0)
const click = () => setN1(n1+1)
const n3 = useMemo(() => {
return n2+100
}, [n2])
return (
<>
<h1 onClick={click} >{n1}</h1>
<h1>{n3}</h1>
</>
)
};
问题: React.memo
在下面情况无法阻止子组件发生渲染
js
const Test = function () {
const [n1, setN1] = useState(0)
const [n2, setN2] = useState(18)
const click = () => setN1(n1+1)
const jack = {age: n2}
return (
<>
<h1 onClick={click} >{n1}</h1>
<Child a={jack} />
</>
)
};
let Child = (props) => {
alert('---render')
return <h1>child: {props.a.age}</h1>
}
Child = React.memo(Child)
解决: 使用useMemo
js
const Test = function () {
const [n1, setN1] = useState(0)
const [n2, setN2] = useState(18)
const click = () => setN1(n1+1)
const jack = useMemo(() => {
return {age: n2}
}, [n2])
return (
<>
<h1 onClick={click} >{n1}</h1>
<Child a={jack} />
</>
)
};
let Child = (props) => {
alert('---render')
return <h1>child: {props.a.age}</h1>
}
Child = React.memo(Child)
useCallback 和 useMemo 的区别:
- useCallback 和 useMemo 都是用于优化的 Hook,但它们用于优化的对象不 同。
- useCallback缓存函数
- useMemo缓存值
- 如果依赖值经常变化, 使用useCallback就没有意义
问题: 即使使用了React.memo
, 父组件更新, 子组件也会更新
js
import { memo, useCallback, useMemo, useState } from "react";
let Child = ({ info }) => {
console.log("---child render");
return <h3>child: {info.name}</h3>;
}
// 子组件使用了 memo 进行浅比较
Child = memo(Child) // <<--------
export default function App() {
const [num, setNum] = useState(0);
const cb = () => {}
return (
<div className="App">
<h1 onClick={() => setNum(num + 1)}>{num}</h1>
<Child cb={cb} />
</div>
);
}
使用useCallback
解决了上面问题
js
import { memo, useCallback, useMemo, useState } from "react";
let Child = ({ info }) => {
console.log("---child render");
return <h3>child: {info.name}</h3>;
}
// 子组件使用了 memo 进行浅比较
Child = memo(Child) // <<--------
export default function App() {
const [num, setNum] = useState(0);
const cb = useCallback(() => {}, []);
return (
<div className="App">
<h1 onClick={() => setNum(num + 1)}>{num}</h1>
<Child cb={cb} />
</div>
);
}
memo有什么用途
shouldComponentUpdate
js
class App extends React.Component {
state = {
count: 1,
};
shouldComponentUpdate(nextProps, nextState) {
if(nextState.count === this.state.count) {
return false
}
return true
}
click = () => {
this.setState({ count: 1 });
};
render() {
console.log('--------render')
return <button onClick={this.click}>{this.state.count}</button>;
}
}
PureComponent
PureComponent
在shouldComponentUpdate
中实现了浅比较(比较最外层属性)
js
class App extends React.PureComponent {
state = {
count: 1,
};
click = () => {
// this.setState({ count: this.state.count+1 });
this.setState({count: 1})
};
render() {
console.log('--------render')
return <button onClick={this.click}>{this.state.count}</button>;
}
}
PureComponent原理
js
class App extends React.Component {
state = {
count: 1,
};
shouldComponentUpdate(nextProps, nextState) {
const hasNotChange =
objEqual(this.props, nextProps) &&
objEqual(this.state, nextState)
if(hasNotChange === true){
return false
}
return true
}
click = () => {
// this.setState({ count: this.state.count+1 });
this.setState({count: 1})
};
render() {
console.log('--------render')
return <button onClick={this.click}>{this.state.count}</button>;
}
}
// 浅比较
function objEqual(oldObj, newObj) {
for(let key in newObj) {
if(oldObj[key] !== newObj[key]) {
return false
}
}
return true
}
memo
函数组件用memo
,实现和 pureComponent
一样的功能
问题:
- 父组件更新, 子组件也触发了更新
- 但是子组件的props并没有发生变化, 并不需要重新渲染
js
import React, { useState, useCallback } from 'react@18';
import { createRoot } from 'react-dom@18/client';
const Test = function () {
const [count1, setCount1] = useState<number>(0);
const handleClick = () => {
setCount1(count1 + 1);
}
return <div onClick={handleClick}>
<h1>click me {count1}</h1>
<Child />
</div>;
};
let Child = (props) => {
alert('-----render')
return <h1>
{props.count}
</h1>
}
解决: 使用Reat.memo
js
import React, { useState, useCallback } from 'react@18';
import { createRoot } from 'react-dom@18/client';
const Test = function () {
const [count1, setCount1] = useState<number>(0);
const handleClick = () => {
setCount1(count1 + 1);
}
return <div onClick={handleClick}>
<h1>click me {count1}</h1>
<Child />
</div>;
};
let Child = (props) => {
alert('-----render')
return <h1>
{props.count}
</h1>
}
Child = React.memo(Child) // <---------------
原理
js
function memo(FnComponent) {
return class Memo extends React.PurComponent {
render(){
return <>{FnComponent(this.props)}</>
}
}
}