というのも中身が同じでもコンポーネントが異なれば DOM は作り直されます
その例です
const Component = () => {
return <div><input/></div>
}
const Foo = () => <Component/>
const Bar = () => <Component/>
const App = () => {
const [foo, toggle] = useReducer(x => !x, false)
const [n, up] = useReducer(x => x + 1, 0)
return (
<div>
<button onClick={toggle}>{foo ? "foo" : "bar"}</button>
<button onClick={up}>{n}</button>
{foo ? <Foo/> : <Bar/>}
</div>
)
}
作り直されたことがわかりやすいように input を配置してます
state で value を管理していないので 作り直されたら入力内容は削除されます
Foo と Bar はどちらも Component を使用して全く同じ動作です
App ではボタンを押すことで Foo と Bar のコンポーネントを切り替えられます
切り替えずに App を再レンダリングするために カウントアップするボタンも置いてます
カウントアップして同じコンポーネントのままだと input は同じ要素のままなので 入力した文字はそのまま残っています
コンポーネントを切り替えると HTML 構造はそのままですが 実際の要素は作り直されて未入力状態に戻っています
key を切り替えたときのような動きです
動的に作るとこういう問題が起きやすいので コンポーネントは静的で props として関数を渡す方法にしたいです
この props に関数を渡すこととコンポーネントを渡すことは似ていて 使う側としては同じように扱えます
<ComponentA
render={
({ name }) => <input name={name} />
}
/>
ComponentA が中で render をどっちとして扱うで動きが違います
const ComponentA = ({ render }) => {
return (
<div>
{render({ name: 1 })}
</div>
)
}
だと 単純に関数を呼び出して結果の React Element が {} に入ります
ComponentA を使うコンポーネントを再レンダリングしても input は残ります
const ComponentA = ({ render: SubComponent }) => {
return (
<div>
<SubComponent name={1} />
</div>
)
}
だと コンポーネントとして扱うことになります
ComponentA を使うコンポーネントが再レンダリングされるとコンポーネントが毎回違うので input の中身が消えます