React と Preact で key の扱いが少し違った
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ React の key はは文字列化される
◆ Preact の key はそのまま
◆ Preact の key はそのまま
React では key が文字列化される
React でリセットのために key を使うと思ったように動きませんでしたリセットされるときとリセットされないときがあります
リセットされる状況からリセットされる条件を考えてみると オブジェクトを key にした場合に 異なるオブジェクトであってもリセットされていないようです
この挙動を見るに オブジェクトであっても文字列化して 「[object Object]」 になってそうです
ソースを見てみると String 型へのキャストがありました
https://github.com/facebook/react/blob/v16.13.1/packages/react/src/ReactElement.js#L368
if (hasValidKey(config)) {
key = '' + config.key;
}
createElement の第二引数で渡す props が config です
Preact との違い
Preact はこういう処理はなくてそのまま渡したものが key として使われますなので単に key を変えて state をクリアしたいときは {} リテラルを set するだけで済みます
オブジェクトの配列から active なものを key として渡すようなときに id プロパティがあるとは限らないですし hyperhtml の wire みたいな感じで オブジェクトで渡したいんですけどね
前にあった React と Preact の違いの onChange を設定しないときの違いは 普通は気にしなくていいものでしたが これは結構影響が大きい違いです
つい Preact の感覚で書いてバグが出る未来が見えます
動かせる React と Preact の比較
input は key が設定されているので適当に入力したあとでボタンを押すと key が変わって入力がクリアされるはずですReact の場合はオブジェクトに置き換えた直後のみリセットされますが それ以降に連続で set object ボタンを押しても変化はありません
<!doctype html>
<meta charset="utf-8" />
<h1>Preact</h1>
<div id="preact"></div>
<hr/>
<h1>React</h1>
<div id="react"></div>
<script src="https://unpkg.com/htm@3.0.4/preact/standalone.umd.js"></script>
<script>
{
const { html, render, useState } = htmPreact
const App = () => {
const [a, setA] = useState(1)
return html`
<div>
<input key=${a} />
<p>key: ${JSON.stringify(a)}</p>
<button onClick=${() => setA({ a: Date.now() })}>set object</button>
<button onClick=${() => setA(Date.now())}>set number</button>
</div>
`
}
render(html`<${App} />`, document.getElementById("preact"))
}
</script>
<script src="https://unpkg.com/htm@3.0.4/dist/htm.js"></script>
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<script>
{
const html = htm.bind(React.createElement)
const { useState } = React
const { render } = ReactDOM
const App = () => {
const [a, setA] = useState(1)
return html`
<div>
<input key=${a} />
<p>key: ${JSON.stringify(a)}</p>
<button onClick=${() => setA({ a: Date.now() })}>set object</button>
<button onClick=${() => setA(Date.now())}>set number</button>
</div>
`
}
render(html`<${App} />`, document.getElementById("react"))
}
</script>