1.useMemo,useCallBack作用
用来做优化,在类组件中,只要父组件进行一个更新,子组件也会进行一个更新。不管子组件应不应该去更新,所以我们需要优化。优化的办法是shouldUpdate这个钩子,父子组件前后传过来的参数进行优化和判断。
2.memo
看下面代码,父组件每次更新的时候,子组件都会相应的去更新。
import React, { useState } from 'react';
const Child = () => {
// const date = new Date();
console.log('i am child');
return (
<div>i am child</div>
// <div>当前时间: {date.getHours()}: {date.getMinutes()}: {date.getSeconds()}</div>
)
};
const Parent = () => {
const [count, setCount] = useState(0);
return (
<div>
count: {count}
<br/>
<button onClick={()=>{
setCount(count + 1)
}}>+1</button>
<Child />
</div>
)
};
function UseRef() {
return (
<div className="App">
<Parent />
</div>
);
}
export default UseRef;
如果不想每次子组件都被迫更新怎么办?
试着给子组件加一个memo,这个memo是判断props如果是相等的,那么就不进行更新。
const Child = memo(() => {
console.log('i am child');
return (
<div>i am child</div>
)
});
接着再试试看,发现不管点击多少次,只有第一次渲染的时候会打印,后面都不会再打印,以内memo里面没有接收任何props,所以会阻止他进行更新
现在举一个有props的例子,看下面
import React, { useState, memo } from 'react';
const Child = memo(() => {
const date = new Date();
console.log('i am child');
return (
// <div>i am child</div>
<div>当前时间: {date.getHours()}: {date.getMinutes()}: {date.getSeconds()}</div>
)
});
const Parent = () => {
const [count, setCount] = useState(0);
const [clickTimeCount, setIimeClickCount] = useState(0);
return (
<div>
count: {count}
<br/>
<button onClick={()=>{
setCount(count + 1)
}}>+1</button>
<button onClick={()=>{
setIimeClickCount(clickTimeCount + 1)
}}>get current time</button>
<Child clickTimeCount={clickTimeCount}/>
</div>
)
};
function UseRef() {
return (
<div className="App">
<Parent />
</div>
);
}
export default UseRef;
看一下效果
点+1控制台不会打印,而且当前时间不变
点get current time控制台会打印,当前时间会变
有没有人和我一样的疑问,child并没有接受这个props啊,其实不管你接不接受这个props,只要你有,就够了
3.useMemo
先看下面的代码
重点将这里修改
<Child clickTimeCount={timeOption}/>
import React, { useState, memo } from 'react';
const Child = memo((props) => {
console.log(props);
const date = new Date();
console.log('i am child');
return (
// <div>i am child</div>
<div>当前时间: {date.getHours()}: {date.getMinutes()}: {date.getSeconds()}</div>
)
});
const Parent = () => {
const [count, setCount] = useState(0);
const [clickTimeCount, setIimeClickCount] = useState(0);
const timeOption = {
clickTimeCount
}
return (
<div>
count: {count}
<br/>
<button onClick={()=>{
setCount(count + 1)
}}>+1</button>
<button onClick={()=>{
setIimeClickCount(clickTimeCount + 1)
}}>get current time</button>
<Child clickTimeCount={timeOption}/>
</div>
)
};
function UseRef() {
return (
<div className="App">
<Parent />
</div>
);
}
export default UseRef;
每次点+1的时候都会打印,明明已经加了memo了,只是timeOption变成了对象了,这是为什么呢?
接下来useMemo登场
const timeOption = useMemo(
() => {
return {
clickTimeCount
}
},
[clickTimeCount]
)
完成代码
import React, { useState, memo, useMemo } from 'react';
const Child = memo((props) => {
console.log(props);
const date = new Date();
console.log('i am child');
return (
// <div>i am child</div>
<div>当前时间: {date.getHours()}: {date.getMinutes()}: {date.getSeconds()}</div>
)
});
const Parent = () => {
const [count, setCount] = useState(0);
const [clickTimeCount, setIimeClickCount] = useState(0);
const timeOption = useMemo(
() => {
return {
clickTimeCount
}
},
[clickTimeCount]
)
return (
<div>
count: {count}
<br/>
<button onClick={()=>{
setCount(count + 1)
}}>+1</button>
<button onClick={()=>{
setIimeClickCount(clickTimeCount + 1)
}}>get current time</button>
<Child clickTimeCount={timeOption}/>
</div>
)
};
function UseMemo() {
return (
<div className="App">
<Parent />
</div>
);
}
export default UseMemo;
如图,点击+1时间不发生改变,点击get current time时间会发生变化。符合预期
可以看出useMemo的作用,可以正确看出值的更新。缓存一些变量。在不需要变化的时候,去读取缓存。
4.useCallback
先看一段代码
import React, { useState, memo } from 'react';
const Child = memo((props) => {
console.log('i am child');
return (
<>
<input type="text" onChange={props.onChange} />
</>
)
});
const Parent = () => {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
const handleChange = (e) => {
setText(e.target.value);
};
return (
<div>
count: {count}
<br/>
<div>text: {text}</div>
<button onClick={()=>{
setCount(count + 1)
}}>+1</button>
<Child onChange={handleChange}/>
</div>
)
};
function UseCallback() {
return (
<div className="App">
<Parent />
</div>
);
}
export default UseCallback;
可见每次向输入框输入的时候,子组件都会执行。原因是,每次输入内容,setText就会执行,这样就会导致父组件进行更新,handleChange也被认为是一个新的,所以导致子组件进行了刷新,但是想想,子组件并不需要这种更新。这个时候需要用useCallback
关键代码
const handleChange = useCallback((e) => {
setText(e.target.value);
}, []);
全部代码
import React, { useState, memo, useCallback } from 'react';
const Child = memo((props) => {
console.log('i am child');
return (
<>
<input type="text" onChange={props.onChange} />
</>
)
});
const Parent = () => {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
const handleChange = useCallback((e) => {
setText(e.target.value);
}, []);
return (
<div>
count: {count}
<br/>
<div>text: {text}</div>
<button onClick={()=>{
setCount(count + 1)
}}>+1</button>
<Child onChange={handleChange}/>
</div>
)
};
function UseCallback() {
return (
<div className="App">
<Parent />
</div>
);
}
export default UseCallback;
这是因为useCallback把函数缓存进来了