本节课我们来学习一下mini-react中的更新和删除,核心就是当type不一致删除旧的创建新的。
举个例子如下图
- div变成p
添加测试代码App.jsx
tsx
import React from './core/React.js';
let showBar = false
function Counter({ num }) {
const Foo = <div>foo</div>
const Bar = <p>bar</p>
function handleShowBar() {
showBar = !showBar
React.update()
}
return <div>
Counter
<div>{showBar ? Bar : Foo}</div>
<button onClick={handleShowBar}>show bar</button>
</div>
}
function App() {
return <div>
hi-mini-react
<Counter></Counter>
</div>
}
export default App;
现在没有实现删除,发现效果如下图

删除策略,把需要删除的节点收集起来,之后再commit的时候统一删除
- 在initChildren函数里面push进deletions数组
tsx
function initChildren(fiber, children) {
ts
children.forEach((child, index) => {
const isSameType = oldFiber && oldFiber.type === child.type
let newFiber
if (isSameType) {
//update
newFiber = {
type: child.type,
props: child.props,
child: null,
parent: fiber,
sibling: null,
dom: oldFiber.dom,
effectTag: "update",
alternate: oldFiber
}
} else {
newFiber = {
type: child.type,
props: child.props,
child: null,
parent: fiber,
sibling: null,
dom: null,
effectTag: "placement"
}
if (oldFiber) {
console.log('oldFiberShouldDelete', oldFiber)
deletions.push(oldFiber)
}
}
})
}
在commitRoot的时候删除
tsx
function commitRoot() {
deletions.forEach(commitDeletion)
commitWork(wipRoot.child)
currentRoot = wipRoot
wipRoot = null
deletions = []
}
function commitDeletion(fiber) {
fiber.parent.dom.removeChild(fiber.dom)
}
- 此再去点击发现没有问题了
特别处理function component的问题,先修改App.jsx
tsx
import React from './core/React.js';
let showBar = false
function Counter({ num }) {
const Foo = () => <div>foo</div>
const Bar = () => <p>bar</p>
function handleShowBar() {
showBar = !showBar
React.update()
}
return <div>
Counter
<div>{showBar ? <Bar /> : <Foo />}</div>
<button onClick={handleShowBar}>show bar</button>
</div>
}
function App() {
return <div>
hi-mini-react
<Counter></Counter>
</div>
}
export default App;
点击按钮发现报错

打断点进行调试发现fiber.dom为null,我们需要删除fiber.child这个div
tsx
function commitDeletion(fiber) {
let fiberParent = fiber.parent
while (!fiberParent.dom) {
fiberParent = fiberParent.parent
}
if (fiber.dom) {
fiberParent.dom.removeChild(fiber.dom)
} else {
commitDeletion(fiber.child)
}
}
