概要
Reactで状態保存とするとuseState, useContext, Redux、Recoilなどがあるが
プロジェクトの規模によってuseStateでは足りない、Redux, Recoilなどでもないと思ったら
useContextが良いと思う。だけと、保存だけでは意味がないのでuseReducerと合わせて管理することを考えられる。ここでuseContextでプロジェクト全般でアクセスできる、useReducerで状態を管理することを考慮しても良いかと思う。
構造
1.初期状態を定義
const initialState = {
....
}
2.管理(追加、更新、削除)アクションの定義
const cartReducer = (state, action) => {
switch(action.type) { case 'ADD_ACTION': ... ... }
}
3. 状態保存(context)を生成
const CartContext = createContext({
... ...
})
4. 供給者(provider)を定義
App.jsやindex.jsでProviderで囲んでは以下のコンポネントで利用する。
const CartProvider = ({ children }) => {
// useReducerでdispatcherを定義
// アクションを呼び出しを用意
// 状態保存を用意
// Providerを返す
}
5. カスタムフックを定義
const useCart = () => useContext(CartContext);
実装例(一部のみ)
1. CartContext <-これが重要
// CartContext.js
import { createContext, useReducer, useContext } from 'react';
// 初期状態
const initialState = {
items: [],
totalAmount: 0,
};
// 管理(追加、更新、削除)アクションの定義
const cartReducer = (state, action) => {
switch (action.type) {
case 'ADD_ITEM':
// ... 詳細は省略 ...
return {
items: updatedItems,
totalAmount: updatedTotalAmount,
};
case 'REMOVE_ITEM':
// ... 詳細は省略 ...
return {
items: removedUpdatedItems,
totalAmount: updatedTotalAmount,
};
default:
return initialState;
}
};
// Context生成
const CartContext = createContext({
items: [],
totalAmount: 0,
addItem: (item) => {},
removeItem: (id) => {},
});
// 供給者(provider)を定義
export const CartProvider = ({ children }) => {
const [cartState, dispatchCartAction] = useReducer(cartReducer, initialState);
const addItemHandler = (item) => {
dispatchCartAction({ type: 'ADD_ITEM', item: item });
};
const removeItemHandler = (id) => {
dispatchCartAction({ type: 'REMOVE_ITEM', id: id });
};
const cartContext = {
items: cartState.items,
totalAmount: cartState.totalAmount,
addItem: addItemHandler,
removeItem: removeItemHandler,
};
return (
<CartContext.Provider value={cartContext}>
{children}
</CartContext.Provider>
);
};
// カスタムフックを定義。
export const useCart = () => useContext(CartContext);
2.App.js
function App() {
return (
<CartProvider>
<Products />
<Cart />
</CartProvider>
</>
);
}
3. Product.js <- アクションなど!
const Products = () => {
const { addItem } = useCart();
const handleAddToCart = (product) => {
addItem({ ...product, amount: 1 });
};
return (
// ... 省略 ..
<button onClick={() => handleAddToCart(product)}>
カートへ追加
</button>
// ... 省略 ..
)
}
4. Cart.js
const Cart = () => {
const { items, totalAmount, removeItem } = useCart();
const handleRemoveFromCart = (id) => {
removeItem(id);
};
return (
<div>
<h2>カート</h2>
// ... 省略 ...(cartのitemの一覧表示、削除ボタン表示)
</div>
)
}