useStateが返すstateをイベントで更新する時に気をつけること

react HooksのuseStateから受け取るstate値をinputフォームなどから発生するイベントで更新する際に、書き方を間違えると落ちてしまう。

落ちる例

export default function InputForm(props: any) {
    const [value, setValue] = useState("");
    
    const onValueChange = useCallback((e) =>{
        setValue(old => {
            return e.target.value;
        });
    }, []);

    return (
        <form>
            <Input placeholder="名前を入力" value={value} onChange={onValueChange}/>
        </form>
    );
}

valueを更新するために、setValueにvalueを更新する関数を渡す書き方。
setValueに渡した関数は、setValueの中で呼び出されるのではなく全然別のタイミングで呼びだされる(スタックトレースをみるとuseStateの内部など?)。
その呼び出されるタイミングですでにe.targe.valueが参照できなくなっている場合がある。そのためこの書き方ではnullアクセスで落ちることがある。

落ちない例

export default function InputForm(props: any) {
    const [value, setValue] = useState("");

    const onValueChange = useCallback((e) => {
        const value = e.target.value;
        setValue(old => {
            return value;
        });
    }, []);

    return (
        <form>
            <Input placeholder="名前を入力" value={value} onChange={onValueChange}/>
        </form>
    );
}

e.target.valueを一旦別の変数(value)に代入しておき、それをキャプチャすれば落ちることはない。

そもそも・・・

この例に限っていえば関数を渡さずに値を渡すのが手っ取り早い。

export default function InputForm(props: any) {
    const [value, setValue] = useState("");

    const onValueChange = useCallback((e) => {
        setValue(e.target.value);
    }, []);

    return (
        <form>
            <Input placeholder="名前を入力" value={value} onChange={onValueChange}/>
        </form>
    );
}

コメント

タイトルとURLをコピーしました