👭
同じcomponentを条件分岐でrenderするとunmountされない
問題
componentが思いがけず再renderされないシチュエーションに遭遇したので記事書きます。
import React from 'react';
const Wrapper: React.FC = props => {
React.useEffect(() => {
console.log('mount Wrapper');
return () => console.log('unmount Wrapper');
}, [])
return(
<div>{props.children}</div>
)
}
const Test: React.FC = (props) => {
const [condition, setCondition] = React.useState(true);
return (
<div>
{condition ? (
<Wrapper>AAA</Wrapper>
) : (
<Wrapper>BBB</Wrapper>
)}
<button onClick={e => setCondition(!condition)}>change</button>
</div>
);
};
export default Test;
このTest
を適当な場所にrenderしてchange
ボタンを繰り返し押すとAAA
とBBB
が交互に表示されますが、consoleの表示はどうなると思います?毎回Wrapperが作り直されて下記のように表示されると思いませんか?
mount Wrapper
# ボタン押す
unmount Wrapper
mount Wrapper
# ボタン押す
unmount Wrapper
mount Wrapper
...
私は思ったのですがmount Wrapper
が一度だけ表示されたきり、何度押しても何も出ません。つまりunmountされません。
解決策
return (
<div>
{condition ? (
<Wrapper key="AAA">AAA</Wrapper>
) : (
<Wrapper key="BBB">BBB</Wrapper>
)}
<button onClick={e => setCondition(!condition)}>change</button>
</div>
);
key
をつけてやれば毎回新しくrenderされます。
これ、気づいてみれば、条件によって<Wrapper>AAA</Wrapper>
か<Wrapper>BBB</Wrapper>
が評価されるだけなので、react的にはchildren
が変わっただけと扱われるのは何となく分からなくはないですが、<Wrapper />
が二つ別々に書いてあるので、別物のような気がしました。
可能な限り使い回すようにできてるんですね。そう考えると凄いな〜と感心します。
Discussion