【保存版】React Hooksでpropsをstateに同期:useState & useEffectを使いこなそう
React Hooks で props を state に同期する方法:setState()
useState の初期値を props に設定
最もシンプルでわかりやすい方法は、useState
フックの初期値を props に設定することです。
const MyComponent = (props) => {
const [state, setState] = useState(props.defaultValue);
// ... コンポーネントのロジック
};
この例では、state
の初期値が props.defaultValue
に設定されています。つまり、コンポーネントが初めてレンダリングされたとき、state
は props の値と一致します。
useEffect フックを使って props の変更を検知
useEffect
フックを使って、props の変更を検知し、それに応じて state を更新する方法もあります。
const MyComponent = (props) => {
const [state, setState] = useState(props.defaultValue);
useEffect(() => {
setState(props.newValue);
}, [props.newValue]);
// ... コンポーネントのロジック
};
この例では、useEffect
フックが props.newValue
の依存関係として指定されています。つまり、props.newValue
が変更されるたびに、useEffect
フックが実行され、state
が新しい値に更新されます。
どちらの方法を使うべき?
どちらの方法を使うべきかは、状況によって異なります。
- props の変更を柔軟に処理したい場合
useEffect
フックを使って props の変更を検知する方法がおすすめです。 - シンプルでわかりやすい方法が必要な場合
useState
の初期値を props に設定する方法がおすすめです。
注意点
useEffect
フックの中でsetState
を呼ぶ場合は、依存関係を適切に設定する必要があります。setState
は非同期処理なので、state
がすぐに更新されるわけではないことに注意が必要です。
const MyComponent = (props) => {
const [count, setCount] = useState(props.initialCount);
return (
<div>
<p>カウント: {count}</p>
<button onClick={() => setCount(count + 1)}>カウントアップ</button>
</div>
);
};
この例では、MyComponent
コンポーネントは initialCount
という props を受け取ります。useState
フックの初期値は props.initialCount
に設定されているので、コンポーネントが初めてレンダリングされたとき、count
state は props の値と一致します。
const MyComponent = (props) => {
const [name, setName] = useState('');
useEffect(() => {
setName(props.newName);
}, [props.newName]);
return (
<div>
<p>名前: {name}</p>
</div>
);
};
この例では、MyComponent
コンポーネントは newName
という props を受け取ります。useEffect
フックの依存関係は props.newName
に設定されているので、props.newName
が変更されるたびに、useEffect
フックが実行され、name
state が新しい値に更新されます。
使い方
const App = () => {
return (
<div>
<MyComponent initialCount={10} />
<MyComponent newName="Taro" />
</div>
);
};
このコードを実行すると、以下の結果が表示されます。
カウント: 10
名前: Taro
useContext
フックを使って、コンポーネント間で state を共有する方法があります。この方法を使うと、props を介さずに、親コンポーネントの state を子コンポーネントで直接利用することができます。
// 親コンポーネント
const MyContext = React.createContext({ count: 0 });
const ParentComponent = () => {
const [count, setCount] = useState(0);
return (
<MyContext.Provider value={{ count, setCount }}>
<ChildComponent />
</MyContext.Provider>
);
};
// 子コンポーネント
const ChildComponent = () => {
const { count, setCount } = useContext(MyContext);
return (
<div>
<p>カウント: {count}</p>
<button onClick={() => setCount(count + 1)}>カウントアップ</button>
</div>
);
};
この例では、MyContext
というコンテキストを作成し、count
と setCount
というプロパティを定義しています。親コンポーネントは MyContext.Provider
コンポーネントを使って、count
と setCount
の値を子コンポーネントに提供します。子コンポーネントは useContext
フックを使って、親コンポーネントから提供された値にアクセスすることができます。
Redux
Redux は、アプリケーション全体の state を管理するためのステートマネジメントライブラリです。Redux を使うと、props を介さずに、コンポーネント間で state を共有することができます。
// store.js
import { createStore } from 'redux';
const initialState = { count: 0 };
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
default:
return state;
}
};
const store = createStore(reducer);
export default store;
// MyComponent.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
const MyComponent = () => {
const count = useSelector((state) => state.count);
const dispatch = useDispatch();
return (
<div>
<p>カウント: {count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>カウントアップ</button>
</div>
);
};
この例では、Redux を使って count
という state を管理しています。MyComponent
コンポーネントは useSelector
フックを使って、Redux store から count
の値を取得し、useDispatch
フックを使って、INCREMENT
というアクションを dispatch することができます。
MobX
// store.js
import { observable, autorun } from 'mobx';
class Store {
@observable count = 0;
increment() {
this.count++;
}
}
const store = new Store();
export default store;
// MyComponent.js
import React from 'react';
import { autorun } from 'mobx';
import store from './store';
const MyComponent = () => {
autorun(() => {
console.log(`カウント: ${store.count}`);
});
return (
<div>
<button onClick={() => store.increment()}>カウントアップ</button>
</div>
);
};
この例では、MobX を使って count
という state を管理しています。MyComponent
コンポーネントは autorun
関数を使って、store.count
の値が変更されるたびに、ログを出力します。
- コンポーネント間で state を共有する必要がある場合
useContext
、Redux、MobX
reactjs react-hooks