起因
事情是这样的,昨天一个组件useMemo依赖太多了,被我一怒之下删掉了,然后就发现组件渲染次数直线上升,我突然顿悟了,我对react hooks一无所知, 然后本着我自己知道的渲染逻辑,写了几个demo,打印完日志之后才发现,我何止一无所知,我写的是什么玩意??
锁匠: 您配钥匙吗?我: 我不配
您配不配钥匙?
下方代码比较多, 但都是无脑的简单代码,还请按照你的理解,跟着我走一遍,看看是不是跟你理解的一样,我是被按在地上打了个细碎
先来看看同步场景
export default function Effect() {
const [name1, updateName1] = useState('name1');
const [name2, updateName2] = useState('name2');
const [name3, updateName3] = useState('name3');
useEffect(() => {
console.log('---1---');
updateName1('name1111');
console.log('---4---');
updateName2('name2222');
console.log('---3---');
updateName3('name3333');
}, []);
console.log('---render---');
return <div style={{ marginTop: '100px' }} className="doc-ui-btns">
<div>name1: {name1}</div>\
<div>name4: {name2}</div>
<div>name3: {name3}</div>
</div>;
}
点击查看执行结果
console.log('---render---');
console.log('---1---');
console.log('---4---');
console.log('---3---');
console.log('---render---');
先来看看同步场景中多个Effect
export default function Effect() {
const [name1, updateName1] = useState('name1');
const [name2, updateName2] = useState('name2');
const [name3, updateName3] = useState('name3');
useEffect(() => {
console.log('---1---');
updateName1('name1111');
}, []);
useEffect(() => {
console.log('---4---');
updateName2('name2222');
}, []);
useEffect(() => {
console.log('---3---');
updateName3('name3333');
}, []);
console.log('---render---');
return <div style={{ marginTop: '100px' }} className="doc-ui-btns">
<div>name1: {name1}</div>\
<div>name4: {name2}</div>
<div>name3: {name3}</div>
</div>;
}
点击查看执行结果
console.log('---render---');
console.log('---1---');
console.log('---4---');
console.log('---3---');
console.log('---render---');
跟写在一个useEffect里面一样
异步场景1: 多个update在异步函数中
export default function Effect() {
const [name1, updateName1] = useState('name1');
const [name2, updateName2] = useState('name2');
const [name3, updateName3] = useState('name3');
useEffect(() => {
setTimeout(() => {
console.log('---1---');
updateName1('name1111');
console.log('---4---');
updateName2('name2222');
console.log('---3---');
updateName3('name3333');
}, 100)
}, []);
console.log('---render---');
return <div style={{ marginTop: '100px' }} className="doc-ui-btns">
<div>name1: {name1}</div>\
<div>name4: {name2}</div>
<div>name3: {name3}</div>
</div>;
}
点击查看执行结果
console.log('---render---');
console.log('---1---');
console.log('---render---');
console.log('---4---');
console.log('---render---');
console.log('---3---');
console.log('---render---');
在异步场景中每次update都会触发render,这个和setState在异步场景的处理一致
是不是感觉简单了?就这?
往后看
同步场景+依赖
function Effect() {
const [name1, updateName1] = useState('name1');
const [name2, updateName2] = useState('name2');
const [name3, updateName3] = useState('name3');
useEffect(() => {
console.log('---1---');
updateName1('name1111');
console.log('---4---');
updateName2('name2222');
console.log('---3---');
updateName3('name3333');
}, []);
useEffect(() => {
console.log('---5---');
updateName2('name2222');
}, [name1]);
useEffect(() => {
console.log('---6---');
updateName2('name3333');
}, [name3]);
console.log('---render---');
return <div style={{ marginTop: '100px' }} className="doc-ui-btns">
<div>name1: {name1}</div>
<div>name4: {name2}</div>
<div>name3: {name3}</div>
</div>;
}
点击查看执行结果
console.log('---render---');
console.log('---1---');
console.log('---4---');
console.log('---3---');
console.log('---5---');
console.log('---6---');
console.log('---render---');
console.log('---5---');
console.log('---6---');
console.log('---render---');
你会发现5 6这两步执行了2遍,并且是合并刷新。
异步场景+依赖
function Effect() {
const [name1, updateName1] = useState('name1');
const [name2, updateName2] = useState('name2');
const [name3, updateName3] = useState('name3');
useEffect(() => {
console.log('---inner---');
setTimeout(() => {
console.log('---1---');
updateName1('name1111');
console.log('---4---');
updateName2('name2222');
console.log('---3---');
updateName3('name3333');
}, 100);
}, []);
useEffect(() => {
console.log('---5---');
updateName3('name2222');
}, [name1]);
useEffect(() => {
console.log('---6---');
updateName2('name3333');
}, [name3]);
console.log('---render---');
return <div style={{ marginTop: '100px' }} className="doc-ui-btns">
<div>name1: {name1}</div>
<div>name4: {name2}</div>
<div>name3: {name3}</div>
</div>;
}
点击查看执行结果
console.log('---render---');
console.log('---inner---');
console.log('---5---');
console.log('---6---');
console.log('---render---');
console.log('---6---');
console.log('---render---');
console.log('---1---');
console.log('---render---');
console.log('---4---');
console.log('---5---');
console.log('---render---');
console.log('---3---');
console.log('---render---');
console.log('---6---');
console.log('---render---');
这里问题出来了,4和5怎么被合并了????这是2个Effect里面的东西啊, 4是在异步状态里面,按照异步场景1: 多个update在异步函数中
这个检测结果,在异步中的事件应该是每update一次,页面就render一次,现在却是4/5合并了!!
这里--5--
这个effect里面正好依赖了异步中第一次修改的name1
, 所以在update name1之后,跟随下一次update,并且在下一次update之后处理了副作用所以就有了先打印4再打印5, 如果吧--6--
里面的依赖改成name2
那么在updateName2之后3和6也会被合并
总结: 在异步操作中,每次update之后的副作用会跟着下一次update执行,并且在下一次update之后执行
异步+依赖场景2 有一次依赖直接被忽略了,没有执行
export default function ToastPage() {
const [name1, updateName1] = useState('name1');
const [name2, updateName2] = useState('name2');
const [name3, updateName3] = useState('name3');
const [name4, updateName4] = useState('name4');
useEffect(() => {
console.log('----第一次变更---');
setTimeout(() => {
console.log('---1---');
updateName1('name1111');
console.log('---2---');
updateName4('name1444444');
console.log('---3---');
updateName3('name133333');
}, 100);
}, []);
useEffect(() => {
console.log('---4---');
updateName3('name333333');
console.log('---5---');
updateName4('name544444');
}, [name1]);
useEffect(() => {
console.log('---6---');
updateName2('name344444');
}, [name4]);
console.log('---render---');
return <div style={{ marginTop: '100px' }} className="doc-ui-btns">
<div>name1: {name1}</div>
<div>name3: {name3}</div>
<div>name4: {name4}</div>
</div>;
}
点击查看执行结果
console.log('---render---');
console.log('----第一次变更---');
console.log('---4---');
console.log('---5---');
console.log('---6---');
console.log('---render---');
console.log('---6---');
console.log('---render---');
console.log('---1---');
console.log('---render---');
console.log('---2---');
console.log('---4---');
console.log('---5---');
// 问题出在这里,执行5之后其实是update了name4 除此之外执行2的时候也更新了name4,但是下方依赖name4变更的6却没有被执行, 而是直接下一步执行了3 然后render就结束了??
console.log('---render---');
console.log('---3---');
console.log('---render---');
上面这个流程,如果把 console.log('---5---'); updateName4('name544444');这两行删掉, --6--这个依赖就会正常执行。
我也不知道为什么...
异步套异步会怎么样?
function ToastPage() {
const [name1, updateName1] = useState('name1');
const [name2, updateName2] = useState('name2');
const [name3, updateName3] = useState('name3');
const [name4, updateName4] = useState('name4');
useEffect(() => {
console.log('----第一次变更---');
setTimeout(() => {
console.log('---1---');
updateName1('name1111');
console.log('---2---');
updateName4('name1444444');
console.log('---3---');
updateName3('name133333');
}, 100);
}, []);
useEffect(() => {
console.log('----变更了name1---');
setTimeout(() => {
console.log('---4---');
updateName3('name333333');
console.log('---5---');
updateName4('name544444');
}, 100);
}, [name1]);
useEffect(() => {
console.log('---6---');
updateName2('name344444');
}, [name4]);
console.log('---render---');
return <div style={{ marginTop: '100px' }} className="doc-ui-btns">
<div>name1: {name1}</div>
<div>name1: {name2}</div>
<div>name3: {name3}</div>
<div>name4: {name4}</div>
</div>;
}
点击查看执行结果
console.log('---render---');
console.log('----第一次变更---');
console.log('----变更了name1---');
console.log('---6---');
console.log('---render---');
//上面是第一阶段,执行完了同步的effect,下面开始执行异步
console.log('---1---');
console.log('---render---');
console.log('---2---');// 这2个合并,
console.log('----变更了name1---'); // 但是合并之后的effect是异步,所以只打印了入口
console.log('---render---'); // 合并之后render
console.log('---3---'); 3 6合并,这时候依然在处理第一个异步
console.log('---6---');
console.log('---render---'); // 合并之后处理异步
console.log('---4---'); // 开始处理第二个异步,这个其实是第一轮执行useEffect的时候产生的
console.log('---render---'); // 遵循了 update一次render一次
console.log('---5---');
console.log('---render---');
console.log('---6---');
console.log('---render---');
console.log('---4---'); // 这是name1变更后又进来了副作用产生的异步操作,但是一次都没有render
console.log('---5---');
没有render
总结一下
上面的执行逻辑中还是有规律可寻的
- 在第一次render结束之后,会执行所有的effect,并且合并同步更新
- 如果在同步的effect中触发了新的同步effect那么会合并更新
- 在异步中,每次update都会触发页面的render
- 在异步中,如果每次update产生了副作用,那么副作用会在下一次update之后合并更新
- 如果是异步update产生的一个异步的effect,那么得等当前所有异步的更新结束之后,才会触发下一次异步事件,这里面就会出现生成多次的情况
我无法理解的场景
- 在
异步+依赖场景2
中,有一次effect为什么会被忽略掉 - 在
异步套异步会怎么样?
中,为什么产生的异步副作用会只update不刷新。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!