1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// useStateはReactのフックで関数コンポーネントで状態管理を行える import { useState } from 'react'; import './App.css' // Appコンポーネントの定義 function App() { // count という状態変数と、その状態を変更するための setCount 関数を作成。setCountは変数countを更新するためのきっかけがなにかを定義する。 // useState は引数として状態の初期値0を受け取り、状態変数をその状態を更新する関数のペアを返す。 // count0 VDOM(前) → count1 VDOM(後) 差分の検出を行う const [count, setCount] = useState(0); // handleClick 関数を定義します。この関数は、ボタンがクリックされたときに呼び出されます。 const handleClick = () => { // handleClick 関数内で setCount を使って count の値を 1 ずつ増やします。(count更新のきっかけ) setCount(count + 1); }; // アプリケーションが表示する JSX を返します。 return ( <div className='App'> <h1>UseState</h1> // ボタンを作成し、handleClick 関数がクリック時に実行されるように設定します。 // onClickは、Reactで使用されるイベントハンドラの一種で、ユーザーが要素をクリックしたときに発生するイベントを処理するために使われます。 <button onClick={handleClick}>+</button> // 現在の count の値を表示する p 要素を作成します。 <p>{count}</p> </div> ); }; // 他のファイルから App コンポーネントをインポートできるように、デフォルトエクスポートします。 export default App; |
1 2 3 4 |
const [count, setCount] = useState(0); const handleClick = () => { count++; }; |
上の例では再レンダリングが発生しない。理由は、Reactが状態変数の変更を検出できなず差分が分からないため。
Reactは、状態が変更されたことを検出するために、状態更新関数(この場合はsetCount
)を使う。状態更新関数を使って状態を変更することで、Reactが状態の変更(差分)を検出し、コンポーネントを再レンダリングすることができる。
1 2 3 |
useEffect(() => { // 行う処理 }, [ここで指定された状態やプロパティが変更されたときにuseEffectが実行される]); |
1 2 3 |
useEffect(() => { console.log("hello"); }, [count]); |
上記例ではcountが変更される度にuseEffectが実行される。[count]は依存配列と呼ばれる。
1 2 3 4 |
useEffect(() => { console.log("hello"); setCount(count + 1); }, [count]); |
上記例はアンチパターン以下解説
countの初期値は0。
コンポーネントがレンダリングされ、useEffectが実行。
useEffect内で、console.log(“hello”)が実行され、setCount(count + 1)によりcountが1に更新。
countが更新されたので、useEffectが再度実行(依存配列にcountが指定されているため)。
useEffect内で、再びcountを更新(この時点でcountは2)。
このプロセスが繰り返され、無限ループが発生。
useContext説明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
// ReactとcreateContextをインポート。createContextは、新しいコンテキストを作成するための関数。 import React, { createContext } from 'react' import ReactDOM from 'react-dom/client' import App from './App.jsx' import './index.css' // gakecodeInfoオブジェクト作成。nameとageはプロパティ。 const gakecodeInfo ={ name: "gakeppuchi", age: 39 }; // createContextを使用して、GakeCodeContextというコンテキスト作成。gakecodeInfoをデフォルト値として指定。 const GakeCodeContext = createContext(gakecodeInfo) // GakeCodeContext.Providerを使って、gakecodeInfoをコンポーネントツリーに提供。 // propsで1つ1つ渡さなくても、どの階層からでもuseContext(GakeCodeContext)を使ってコンポーネントにアクセルできる。 ReactDOM.createRoot(document.getElementById('root')).render( <GakeCodeContext.Provider value = {gakecodeInfo}> <React.StrictMode> <App /> </React.StrictMode> </GakeCodeContext.Provider> ); // GakeCodeContextをエクスポート。これにより、他のコンポーネントでuseContext(GakeCodeContext)を使ってこのコンテキストにアクセスできる。 export default GakeCodeContext; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
// hooksのインポート import { useEffect,useState, useContext } from 'react'; import './App.css' // GakeCodeContextをインポート main.jsxのuseContext(GakeCodeContext)を使える // main.jsx の export default GakeCodeContext; と連動 import GakeCodeContext from './main'; function App() { const [count, setCount] = useState(0); // Appコンポーネントの中で、useContext(GakeCodeContext)を使ってgakecodeInfoオブジェクトにアクセス。 const gakecodeInfo = useContext(GakeCodeContext); const handleClick = () => { setCount(count + 1); }; useEffect(() => { console.log("hello") //setCount(count + 1); }, [count]); return ( <div className='App'> <h1>useState, useEffect</h1> <button onClick={handleClick}>+</button> <p>{count}</p> <hr /> <h1>useContext</h1> {/* gakecodeInfoのname,ageを表示→useContextでmain.jsxと繋がっているから使用可能*/} <p>{gakecodeInfo.name}</p> <p>{gakecodeInfo.age}</p> </div> ); }; export default App; |
GakeCodeContext.Provider
を使用してgakecodeInfo
オブジェクトをコンポーネントツリーに提供する目的は、コンポーネント間で共有したいデータを簡単にアクセスできるようにするためです。
従来の方法では、プロパティ(props)を介してデータを子コンポーネントに渡す必要がありますが、非効率的です。
コンテキストシステムは、GakeCodeContext.Provider
を使ってデータを提供することで、コンポーネントツリー内のどのコンポーネントでも、useContext(GakeCodeContext)
フックを使ってそのデータにアクセスできます。これにより、データを必要とするコンポーネントだけがデータにアクセスでき、かつ親から子へとプロパティを継続的に渡す必要がなくなります。