Reactにおける子コンポーネントからの親の状態変更
前のレッスンでは、データの状態は親コンポーネントに保存され、 子コンポーネントはpropsとしてそのデータを受け取っていました。
さて、今度は商品を変更したいとしましょう。
例えば、商品をカートに入れるボタンを作りましょう。
まず、商品の配列に、商品がカート内にあるかどうかを示す
フィールド inCart を追加します:
const initProds = [
{id: id(), name: 'product1', cost: 100, inCart: false},
{id: id(), name: 'product2', cost: 200, inCart: false},
{id: id(), name: 'product3', cost: 300, inCart: false},
];
コンポーネント Products で、商品のタグに
属性 inCart を追加します:
function Products() {
const [prods, setProds] = useState(initProds);
const items = prods.map(prod => {
return <Product
key ={prod.id}
name ={prod.name}
cost ={prod.cost}
inCart={prod.inCart}
/>;
});
return <div>
{items}
</div>;
}
子コンポーネント Product で、
カート情報の表示とカート追加ボタンを作りましょう:
function Product({ id, name, cost, inCart }) {
return <div>
name: <span>{name}</span>,
cost: <span>{cost}</span>,
<span>{inCart ? 'in cart' : 'not in cart'}</span>
<button>to cart</button>
</div>;
}
追加機能を実装する
Reactのルールでは、コンポーネントは自身のpropsを変更してはなりません。
これは、子コンポーネントがprop inCart を変更して
自身をカートに入れることができないことを意味します。
これは正しくありません。
正しい方法は、親コンポーネントに要求し、親コンポーネント自身の状態
prods を変更して、特定の商品をカートに入れることです。
では、その方法を見てみましょう。
親コンポーネントで、商品の id をパラメータとして受け取り、
その商品のプロパティ inCart を true に変更する
関数 addToCart を作成します:
function addToCart(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.inCart = true;
}
return prod;
}));
}
商品のタグに、作成した関数を渡す属性と、
商品の id を渡す属性を追加します:
const items = prods.map(prod => {
return <Product
key ={prod.id}
id ={prod.id}
name ={prod.name}
cost ={prod.cost}
inCart ={prod.inCart}
addToCart={addToCart}
/>;
});
ご覧の通り、コンポーネントのpropsにはデータだけでなく、 関数も渡すことができます。
クラス Products の最終的なコードは以下のようになります:
function Products() {
const [prods, setProds] = useState(initProds);
function addToCart(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.inCart = true;
}
return prod;
}));
}
const items = prods.map(prod => {
return <Product
key ={prod.id}
id ={prod.id}
name ={prod.name}
cost ={prod.cost}
inCart ={prod.inCart}
addToCart={addToCart}
/>;
});
return <div>
{items}
</div>;
}
これで、子クラスでは関数 addToCart が利用可能になります。
ボタンのクリック時にこの関数を呼び出し、商品の id を
パラメータとして渡します:
function Product({ id, name, cost, inCart, addToCart }) {
return <div>
name: <span>{name}</span>,
cost: <span>{cost}</span>,
<span>{inCart ? 'in cart' : 'not in cart'}</span>
<button onClick={() => addToCart(id)}>to cart</button>
</div>;
}
結果として、子コンポーネントのボタンをクリックすると 親の関数が呼び出され、親の状態が変更されます。 親の状態の変更は再レンダリングを引き起こし、 変更されたpropを渡して商品を再描画します。
前のレッスンの User コンポーネントを使用してください。
ユーザーをBANするためのボタンを追加してください。