簡易 React 自作 で 分かりづらかったところ

# 簡易 React 自作 を試してみて
React 自作の記事があったので、試してみました。

https://zenn.dev/akatsuki/articles/a2cbd26488fa151b828b

ただ、やってみて分かりづらい部分が多々あったので、そのまとめをします。

### reconcileChildren の中の prevSibling.sibling = newFiber ってなんだ？

```javascript
if (index === 0) {
	wipFiber.child = newFiber
} else {
    prevSibling.sibling = newFiber
}
prevSibling = newFiber
```

これは github に答えがありました。

https://github.com/pomber/didact/issues/20

１：まず、初回のループ(index === 0)の時は、wipFiber.child に 初回の newFiber を追加して、prevSibling に 初回の newFiber を代入します。
２：次のループ(index === 1)の時は、prevSibling に入っている 初回の newFiber の siblingプロパティーに 2回目の newFiber が代入されます。そして、prevSibling に 2回目の newFiber が代入されます。
３：その次以降のループも同じようになる。

言ってしまえば、簡単ですね。
これで、各 parent と 最初の各children のみが連結され、sibling は 最初の child から数珠繋ぎになっている、二重連鎖木 ができますね。

https://ja.wikipedia.org/wiki/%E4%BA%8C%E9%87%8D%E9%80%A3%E9%8E%96%E6%9C%A8

### alternate って、最初の render の時にしか定義されていないような・・・？
alternate と言えば、reconcileChildren で古いFiber と新しいFiberを比較するためのプロパティですね。

このalternate、コードを読むと代入されている部分が３箇所のみで、使われているのが２箇所のみになっています（「Step6：差分検出」まででは）。

代入されている部分
```javascript:初回render時
function render(element, container) {
	wipRoot = {
		dom: container,
		props: {
			children: [element]
		},
		alternate: currentRoot
	}
	deletions = []
	nextUnitOfWork = wipRoot
}
```

```javascript:ノードの更新時
if (sameType) {
	// TODO Update node
	newFiber = {
		type: oldFiber.type,
		props: element.props,
		dom: oldFiber.dom,
		parent: wipFiber,
		alternate: oldFiber,
		effectTag: "UPDATE"
	}
}
```

```javascript:ノードの作成時
if (element && !sameType) {
	// TODO Add node
	newFiber = {
		type: element.type,
		props: element.props,
		dom: null,
		parent: wipFiber,
		alternate: null,
		effectTag: "PLACEMENT"
	}
}
```

使われている部分

```javascript:旧Fiber の 取得
let oldFiber = wipFiber.alternate && wipFiber.alternate.child
```

```javascript:旧Fiber の Props を取得
updateDom(fiber.dom, fiber.alternate.props, fiber.props)
```

ここで、一度 "PLACEMENT" が終わった後で、再レンダリングし "UPDATE" が行われた場合を考える。

```javascript: onInput で 再レンダリング
// UseCase2
const onInputWord = (event) => {
	rerender(event.target.value)
}
const container = document.getElementById("root")
const rerender = value => {
	const element = Didact.createElement(
		"div",
		{ id: "foo"},
		Didact.createElement("a", null, Didact.createElement("h2", null, "bar")),
		Didact.createElement("br"),
		Didact.createElement("b", null,
			Didact.createElement("h4", null,
				Didact.createElement("i", null, `Hello ${value}`)
			)
		),
		Didact.createElement("br"),
		Didact.createElement("input", {onInput: onInputWord, defaultValue: value})
	)
	Didact.render(element, container)
}
rerender("World")
```

この使われている部分の wipFiber.alternate && wipFiber.alternate.child が、初回 render時 の alternate が代入されている時に入るのは分かるが、次の wipFiber.child が nextUnitOfWork に入る

```javascript
if (fiber.child) {
	return fiber.child
}
```

では、どうなっているか分かりづらい。

ただ、ここの順番は、

```javascript
const elements = fiber.props.children
reconcileChildren(fiber, elements)

if (fiber.child) {
	return fiber.child
}
```

レコンサイル (reconcileChildren) して、fiber に child オプションなどを付与してから 次の performUnitOfWork に移っているので、次の performUnitOfWork の中の reconcileChildren では alternate が null になることはない。

初回の render 時のレコンサイルから説明すると、render して alternate が付与された nextUnitOfWork = wipRoot は、まず nextUnitOfWork が null でなくなったので、performUnitOfWork で reconcileChildren します。
reconcileChildren では、wipRoot が wipFiber に入っているので、oldFiber には null は入りません。
ここで、sameType の判定が入りますが、ここでは oldFiber に入っている alternate.child と element[0] は同じなので（wipRootの子要素のtypeが変わっていない限り。なお今回のインプットフォームではwipRootの子要素のtypeは変わりません）、alternate に oldFiber が入った newFiber が作成され、wipFiber の child に newFiber が代入されます。
二回目の index の while では、wipRootの子要素のtypeが変わっていないので、上とほぼ同じですが、prevSibling の sibling に newFiber が代入されます。

この reconcileChildren が終了すると、child が見つかる場合は performUnitOfWork (fiber.child) が実行されますが、ここの fiber.child にも 二度目の rerender 時には alternate が付与されています。
Sibling の場合にも、二度目の rerender 時には alternate が付与されます。
reconcileChildren の後で if (fiber.child) している順番通りです。

まとめると、

```javascript
const elements = fiber.props.children
reconcileChildren(fiber, elements)

if (fiber.child) {
	return fiber.child
}
// 省略
			return nextFiber.sibling
```

の順番通り、reconcileChildren で child と sibling に alternate が入った newFiber を代入してから、return される child と 各sibling で performUnitOfWork (nextUnitOfWork) をします。