前言
React Diff 算法为了将复杂度降低到 O(n),提出了以下几种优化方式:
- 只对比统一层级的节点
- 只对同一种类型对比
- 只对同样的 key 对比(没有设置就都认为 key 是 undefined)
要实现的例子如下,通过点击 “btn” 按钮可以切换显示隐藏 “a” 这个组件。通过这个例子我们可以观察不同实现方式对子组件的影响。根据子组件挂载和卸载打印的日志,你能清楚的知道为什么输出内容不一样你就算学明白 React Diff 机制了。
我们先实现 a/b/c 的公共组件,它在挂载和卸载的时候会打印一下 log。
function Comp({ name }) {
useEffect(() => {
console.log('mount:', name);
return () => {
console.log('remove:', name);
};
}, []);
return <div>{name}</div>;
}
复制代码
观察以下几种实现的差异
方式一
常规实现方式:
const App = () => {
const [isShow, setShow] = useState(true);
return (
<div>
<button onClick={() => setShow(!isShow)}>btn</button>
{isShow && <Comp name="a" />}
<Comp name="b" />
<Comp name="c" />
</div>
);
};
复制代码
点击两次按钮查看日志:
# 挂载 >>>
mount: a
mount: b
mount: c
# 点击1 >>>
remove: a
# 点击2 >>>
mount: a
复制代码
方式二
此实现方式和上一个 demo 有什么区别呢?
const App = () => {
const [isShow, setShow] = useState(true);
if (isShow) {
return (
<div>
<button onClick={() => setShow(!isShow)}>btn</button>
<Comp name="a" />
<Comp name="b" />
<Comp name="c" />
</div>
);
}
return (
<div>
<button onClick={() => setShow(!isShow)}>btn</button>
<Comp name="b" />
<Comp name="c" />
</div>
);
};
复制代码
点击两次按钮查看日志:
# 挂载 >>>
mount: a
mount: b
mount: c
# 点击1 >>>
remove: c
# 点击2 >>>
mount: c
复制代码
方式三
不同类型在位置变化的情况下是如何执行?
const Comp1 = props => <Comp {...props} />;
const Comp2 = props => <Comp {...props} />;
const Comp3 = props => <Comp {...props} />;
const App = () => {
const [isShow, setShow] = useState(true);
if (isShow) {
return (
<div>
<button onClick={() => setShow(!isShow)}>btn</button>
<Comp1 key="a" name="a" />
<Comp2 name="b" />
<Comp3 name="c" />
</div>
);
}
return (
<div>
<button onClick={() => setShow(!isShow)}>btn</button>
<Comp2 name="b" />
<Comp3 name="c" />
</div>
);
};
复制代码
点击两次按钮查看日志:
# 挂载 >>>
mount: a
mount: b
mount: c
# 点击1 >>>
remove: a
remove: b
remove: c
mount: b
mount: c
# 点击2 >>>
remove: b
remove: c
mount: a
mount: b
mount: c
复制代码
方式四
加上 key 之后的变化:
const Comp1 = props => <Comp {...props} />;
const Comp2 = props => <Comp {...props} />;
const Comp3 = props => <Comp {...props} />;
const App = () => {
const [isShow, setShow] = useState(true);
if (isShow) {
return (
<div>
<button onClick={() => setShow(!isShow)}>btn</button>
<Comp1 name="a" />
<Comp2 key="b" name="b" />
<Comp3 key="c" name="c" />
</div>
);
}
return (
<div>
<button onClick={() => setShow(!isShow)}>btn</button>
<Comp2 key="b" name="b" />
<Comp3 key="c" name="c" />
</div>
);
};
复制代码
点击两次按钮查看日志:
# 挂载 >>>
mount: a
mount: b
mount: c
# 点击1 >>>
remove: a
# 点击2 >>>
mount: a
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END