ロードマップ
React 16.8 で追加された機能であるReactのHooks
について書いてあります。
書きながら学ぶ React Hooks 入門シリーズとして書き下ろしました。
はじめに
Reactの組み込みフックであるuseState
の説明をします。
useState とは
state と stateの更新関数を返すフックです。
このフックを利用すれば、コンポネント内でstate管理ができます。
state が 更新されるとコンポネントは再レンダリングされます。
構文
const [state, setState] = useState(state初期値)
活用例...カウントアプリ
サンプルコード
import React, { useState } from "react";
const App = () => {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
return (
<div className="App">
<p>{count}</p>
<button onClick={increment}>+1</button>
</div>
);
};
export default App;
活用例...カウントアプリ(setStateの更新関数の引数に関数を渡すバージョン)
サンプルコード
import React, { useState } from "react";
const App = () => {
const [count, setCount] = useState(0);
const increment = () => setCount((currentCount) => currentCount + 1);
return (
<div className="App">
<p>{count}</p>
<button onClick={increment}>+1</button>
</div>
);
};
export default App;
これの何が嬉しいのか? => ロジックをコンポネントの外に切り出せる
これによって、ロジックが外部に依存しにくくなります。また、共通化しやすくなるメリットもあります。
サンプルコード(setStateの引数に渡した関数を外部化)
import React, { useState } from "react";
const App = () => {
const [count, setCount] = useState(0);
const increment = () => setCount((currentCount) => currentCount + 1);
return (
<div className="App">
<p>{count}</p>
<button onClick={increment}>+1</button>
</div>
);
};
export default App;
最初に書いたsetStateの引数だと、setState(count + 1)
だと、外部に切り出せませんが
setStateの更新関数の引数に関数を渡すバージョンだと、コンポネント外に切り出せます。
import React, { useState } from "react";
// setState内のロジックを外部化
const updateCount = (currentCount) => currentCount + 1;
const App = () => {
const [count, setCount] = useState(0);
const increment = () => setCount(updateCount);
return (
<div className="App">
<p>{count}</p>
<button onClick={increment}>+1</button>
</div>
);
};
export default App;
活用例...オブジェクトをどう扱うか
本の情報を扱う object を state にして表示してみましょう。
サンプルコード
import React, { useState } from "react";
const bookInfo = {
title: "サピエンス全史",
author: "ユヴァル・ノア・ハラリ",
price: 2000
};
const App = () => {
const [book, setBook] = useState(bookInfo);
// 値が更新される関数
const updateBookInfo = () => setBook({ ...book, price: book.price + 1 });
// 値が更新されない関数
const updateBookInfo2 = () => {
book.price = book.price = 1;
setBook(book);
};
return (
<div className="App">
<p>{book.title}</p>
<p>{book.author}</p>
<p>{book.price}</p>
<button onClick={updateBookInfo}>update</button>
</div>
);
};
export default App;
仮に、...book,
を消してしまい、関数updateBookInfo
が以下のようだと...
const updateBookInfo = () => setBook({ price: book.price + 1 });
setState 更新後の値は、{price: 2001}
と、priceだけになるでしょう。これは、setStateが差分だけマージじゃなく置換だからです。
注意点
buttonクリック時の関数を
- 関数
updateBookInfo
にすると、値は更新される - 関数
updateBookInfo2
にすると、値は更新されない
原因は updateBookInfo2
に渡された book
が変更前と同じとみなされたからです。
React の state は Object.is()
で変更の有無を判定しているらしいです。
-
Object.is()
が true なら 同じ(変更してない)と見なして Reactの場合コンポネントが再レンダリングされない -
Object.is()
が false なら 変更したと見なして Reactの場合コンポネントが再レンダリングされる - だけど、stateの中身は更新されます。コンポネントが再レンダリングされないからユーザーの目には変わってないように見えます
Object.is
に関しては、以下が参考になりました。
一方で、関数updateBookInfo
は、スプレッド演算子を利用して新たなオブジェクトを生成しているのでObject.is()
の結果はfalseになりコンポネントが再レンダリングされます。
これは、setState
関数が配列の場合でも同じです。
今回は以上です。
参考