当サイトは、アフィリエイト広告を利用しています

useStateの使い方(応用編)

作成日:2022月03月05日
更新日:2023年12月04日

useStateの使い方のサンプルをいくつかまとめておく。
useStateの基本的な使い方にについては下記記事で紹介しています

オブジェクト(連想配列)の場合

useStateのstateをオブジェクトにすることができる。 初期値設定時にオブジェクトを設定する。

定義

jsx
//オブジェクトのkeyが決まってる場合
const [form, setForm] = useState({ email: '', password: '' });
//何もなしでも可能
const [form, setForm] = useState({});

state更新関数

戻り値を新規オブジェクトで返却する。
戻り値のオブジェクト内で引数(prevState)でもらった更新前のstateを
スプレッド構文で展開する。
展開後にeventの値で同じkeyのvalueを更新するイメージ。
※実際は直前のstateから新規オブジェクトを作っている。

event内で直接記述する場合

イベント発生時に直接、state更新関数を呼ぶ。 eventの値をstate更新関数で使用してたい場合は下記のようにonChange内の引数にイベントを設定した
アロー関数の中でstate更新関数を呼ぶようにする。
※state更新関数で引数にとれるのは直前のstateのみのため

state更新関数
import "./styles.css";
import React, { useState } from 'react'
export default function App() {
const [form, setForm] = useState({});
return (
<div>
<label>
メールアドレス:
<input
name="email"
type="email"
onChange={(e) => {
setForm((prevState) => {
return {
...prevState,
[e.target.name]: e.target.value,
}
})
}}
/>
</label>
{form.email}
</div>
);
}

別の関数経由でstate更新関数を呼ぶ場合

handleChange内でstate更新関数を使う。
イベント時にはhandleChangeを呼ぶようにする

state更新関数
import "./styles.css";
import React, { useState } from 'react'
export default function App() {
const [form, setForm] = useState({});
const handleChange = (e) => {
setForm((prevState) => {
return {
...prevState,
[e.target.name]: e.target.value,
};
});
};
return (
<div>
<label>
メールアドレス:
<input
name="email"
type="email"
onChange={handleChange}
/>
</label>
{form.email}
</div>
);
}

参考

初心者でもわかるReact Hook のuseStateを使い方  

React Hooks での form の扱い方  

配列の場合

useStateのstateに配列を設定することができる。 初期値設定時に配列を設定する。

定義

jsx
//useStateの初期値
const initialState = [
"baseboll",
"soccer",
"basketball",
"volleyball",
"tennis"
];
// useState
const [sports, setSports] = useState(initialState);

state更新関数

state更新に関してはオブジェクト同様にevent内に直接記述することや
他の関数経由で呼ぶことできる。
※オブジェクトの場合とほぼ同じようなコードになるのでここでは省略

stateの配列に新しい値を追加する場合

setStateで直前のstateをスプレッド構文で展開した分 + 追加項目で新しい配列を作るようする

jsx
import { useState, useRef } from "react";
export default function App() {
//useStateの初期値
const initialState = [
"baseboll",
"soccer",
"basketball",
"volleyball",
"tennis"
];
// useState
const [sports, setSports] = useState(initialState);
//useRefでinputと紐づけ
const inputElement = useRef(null);
// 追加処理
//現状のstateをスプレッド構文で展開した分 + 追加項目で新しい配列を作る
//返却値として新しい配列を返す
const addSports = () => {
setSports([...sports, inputElement.current.value]);
};
return (
<div className="App">
<h1>Sample</h1>
<input type="text" name="atext" ref={inputElement} />
<button onClick={addSports}>追加する</button>
<ul>
{sports.map((sport) => {
return <li>{sport}</li>;
})}
</ul>
</div>
);
}

stateの配列の値を更新する場合

state配列の値を更新したい場合は、setSportsでラムダ式のmapを使って
配列内の更新対象を更新した新しい配列を設定するようにする。
※mapは配列に任意の処理をした新しい配列を戻り値として返すため

jsx
import { useState, useRef } from "react";
export default function App() {
//useStateの初期値
const initialState = [
"baseboll",
"soccer",
"basketball",
"volleyball",
"tennis"
];
// useState
const [sports, setSports] = useState(initialState);
//useRefでinputと紐づけ
const inputElement = useRef(null);
const taregetInputElement = useRef(null);
const updateInputElement = useRef(null);
// 追加処理
//現状のstateをスプレッド構文で展開した分 + 追加項目で新しい配列を作る
//返却値として新しい配列を返す
const addSports = () => {
setSports([...sports, inputElement.current.value]);
};
 //更新処理
//mapで更新対象を更新した新しい配列を返却する
const updateSportsList = () => {
setSports(
sports.map((sport) =>
sport === taregetInputElement.current.value
? updateInputElement.current.value
: sport
)
);
};
return (
<div className="App">
<h1>Sample</h1>
<input type="text" name="atext" ref={inputElement} />
<button onClick={addSports}>追加する</button>
<ul>
{sports.map((sport) => {
return <li>{sport}</li>;
})}
<div>
<label>更新対象</label>
<input type="text" name="atext" ref={taregetInputElement} />
</div>
<div>
<label>更新項目</label>
<input type="text" name="atext" ref={updateInputElement} />
</div>
<button onClick={updateSportsList}>更新する</button>
</ul>
</div>
);
}

stateの配列から値を削除する場合

state配列の値を削除したい場合は、setSportsでラムダ式のfilterを使って
配列内の削除対象を除いた新しい配列を設定するようにする。

jsx
import { useState, useRef } from "react";
export default function App() {
//useStateの初期値
const initialState = [
"baseboll",
"soccer",
"basketball",
"volleyball",
"tennis"
];
// useState
const [sports, setSports] = useState(initialState);
//useRefでinputと紐づけ
const inputElement = useRef(null);
const taregetInputElement = useRef(null);
const updateInputElement = useRef(null);
// 追加処理
//現状のstateをスプレッド構文で展開した分 + 追加項目で新しい配列を作る
//返却値として新しい配列を返す
const addSports = () => {
setSports([...sports, inputElement.current.value]);
};
//更新処理
//mapで更新対象を更新した新しい配列を返却する
const updateSportsList = () => {
setSports(
sports.map((sport) =>
sport === taregetInputElement.current.value
? updateInputElement.current.value
: sport
)
);
};
// 削除処理
//filterで削除対象以外を除いた新しい配列を返却する
const delSportsList = () => {
setSports(sports.filter((sport) => sport !== inputElement.current.value));
};
return (
<div className="App">
<h1>Sample</h1>
<input type="text" name="atext" ref={inputElement} />
<button onClick={addSports}>追加する</button>
<button onClick={delSportsList}>削除する</button>
<ul>
{sports.map((sport) => {
return <li>{sport}</li>;
})}
<div>
<label>更新対象</label>
<input type="text" name="atext" ref={taregetInputElement} />
</div>
<div>
<label>更新項目</label>
<input type="text" name="atext" ref={updateInputElement} />
</div>
<button onClick={updateSportsList}>更新する</button>
</ul>
</div>
);
}

参考

まとめ

基本的にstateに配列やオブジェクトを設定している場合、追加、削除、更新をする場合は
スプレッド構文やラムダ式(mapやfilterなど)を利用して新しく作りなおすようにする。
理由としては、reactではstateやpropsの値が変化した時にコンポーネントの再描画が行われるため
pushやspliceでは再描画されないため。
※Objects.isメソッドで判定しているらしい。

参考

【React】 useStateで配列を保存するときの注意点  

新着記事

タグ別一覧
top