Reactにおける親コンポーネントのステートを子コンポーネントで編集する方法
次に、入力フィールドを使用して商品を編集できるようにしましょう。 そのために、子コンポーネントにボタンを追加します。
このボタンを最初にクリックしたとき、商品の名前と価格の代わりに 編集用の入力フィールドが表示され、もう一度クリックすると 入力フィールドが再びテキストに戻るようにします。
商品の配列に isEdit プロパティを追加して変更を加えましょう
(シンプルにするためにカートの機能は削除します):
const initProds = [
{id: id(), name: 'product1', cost: 100, isEdit: false},
{id: id(), name: 'product2', cost: 200, isEdit: false},
{id: id(), name: 'product3', cost: 300, isEdit: false},
];
Productコンポーネント
商品コンポーネントに編集用のボタンを作成します:
function Product({ id, name, cost, isEdit }) {
return <div>
name: <span>{name}</span>
cost: <span>{cost}</span>
<button>edit</button>
</div>;
}
このボタンをクリックしたときに、親コンポーネントから渡された
ある関数 toggleMode が呼び出されるようにしましょう:
function Product({ id, name, cost, isEdit, toggleMode }) {
return <div>
name: <span>{name}</span>
cost: <span>{cost}</span>
<button onClick={() => toggleMode(id)}>
edit
</button>
</div>;
}
まだ toggleMode の実装はありませんが、
この関数は親コンポーネントに配置され、
パラメータとして商品の id を受け取り、
商品の isEdit プロパティを反転させるものであることがわかっています。
また、ボタンのテキストがクリックごとに変わるようにしましょう:
function Product({ id, name, cost, isEdit, toggleMode }) {
return <div>
name: <span>{name}</span>
cost: <span>{cost}</span>
<button onClick={() => toggleMode(id)}>
{isEdit ? 'save': 'edit'}
</button>
</div>;
}
編集モードの時はデータが入力された入力フィールドを、 通常モードの時はspan要素を表示するようにしましょう:
function Product({ id, name, cost, isEdit, toggleMode }) {
return <div>
name: {isEdit ? <input value={name} /> : <span>{name}</span>}
cost: {isEdit ? <input value={cost} /> : <span>{cost}</span>}
<button onClick={() => toggleMode(id)}>
{isEdit ? 'save': 'edit'}
</button>
</div>;
}
入力フィールドに onChange イベントをバインドし、
その中で親コンポーネントの関数 editProd を呼び出すようにします:
function Product({ id, name, cost, isEdit, toggleMode, editProd }) {
return <div>
name: {
isEdit
? <input value={name} onChange={event => editProd(id, 'name', event)} />
: <span>{ name }</span>
}
cost: {
isEdit
? <input value={cost} onChange={event => editProd(id, 'cost', event)} />
: <span>{ cost }</span>
}
<button onClick={() => toggleMode(id)}>
{isEdit ? 'save': 'edit'}
</button>
</div>;
}
Productsコンポーネント
次に、Products コンポーネントに移りましょう。
ここで関数 toggleMode を実装します:
function toggleMode(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.isEdit = !prod.isEdit;
}
return prod;
}));
}
また、関数 editProd もここで実装します:
function editProd(id, field, event) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod[field] = event.target.value;
}
return prod;
}));
}
商品タグに属性として関数 toggleMode と editProd を渡します:
const items = prods.map(prod => {
return <Product
key ={prod.id}
id ={prod.id}
name={prod.name}
cost={prod.cost}
isEdit={prod.isEdit}
toggleMode={toggleMode}
editProd={editProd}
/>;
});
Products コンポーネントの最終的なコードは次のようになります:
function Products() {
const [prods, setProds] = useState(initProds);
function toggleMode(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.isEdit = !prod.isEdit;
}
return prod;
}));
}
function editProd(id, field, event) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod[field] = event.target.value;
}
return prod;
}));
}
const result = prods.map(prod => {
return <Product
key ={prod.id}
id ={prod.id}
name={prod.name}
cost={prod.cost}
isEdit={prod.isEdit}
toggleMode={toggleMode}
editProd={editProd}
/>;
});
return <div>
{result}
</div>;
}
実践タスク
前のレッスンで作成した Users コンポーネントと User コンポーネントに対しても、
同様の操作を実行してください。