React에서 자식 컴포넌트의 상태를 통한 작업 모드
이제 우리의 제품 배열이 다음과 같이 생겼다고 가정해 봅시다:
const initProds = [
{id: id(), name: 'prod1', cost: 'cost1', catg: 'catg1'},
{id: id(), name: 'prod2', cost: 'cost2', catg: 'catg2'},
{id: id(), name: 'prod3', cost: 'cost3', catg: 'catg3'},
];
이 제품들을 HTML 테이블로 출력해 봅시다.
그리고 테이블의 어떤 셀을 클릭해도 해당 셀에
편집을 위한 입력 필드가 나타나도록 만들어 봅시다.
이 문제를 해결하기 위해 3개의 컴포넌트를
만들겠습니다.
Products 컴포넌트는 제품들을 담은 상태를
저장하고, 제품을 출력하기 위해 Product
컴포넌트를 사용할 것입니다. Product 컴포넌트는
차례로 특정 제품 필드(이름, 가격, 카테고리)를
출력하기 위해 ProductField 컴포넌트를
사용할 것입니다.
ProductField 컴포넌트는 필드의 텍스트를
보여주거나, 편집을 위한 입력 필드를 보여줄 것입니다.
이때 편집 모드 또는 표시 모드는 이 컴포넌트 자체의
상태에 의해 제어됩니다.
즉, 우리는 이 모드를 부모 상태에 저장하지 않을 것입니다. 거기에 저장하는 것은 매우 불편할 것입니다. 왜냐하면 각 제품 필드에 대한 모드를 지정해야 하기 때문이며, 이는 우리의 상태를 다음과 비슷한 것으로 만들어 버릴 것입니다:
const initProds = [
[
{field: 'name', value: 'prod1', isEdit: false},
{field: 'cost', value: 'cost1', isEdit: false},
{field: 'catg', value: 'catg1', isEdit: false},
],
[
{field: 'name', value: 'prod2', isEdit: false},
{field: 'cost', value: 'cost2', isEdit: false},
{field: 'catg', value: 'catg2', isEdit: false},
],
[
{field: 'name', value: 'prod3', isEdit: false},
{field: 'cost', value: 'cost3', isEdit: false},
{field: 'catg', value: 'catg3', isEdit: false},
],
]
하지만 우리는 그런 상태를 만들지 않고, 원래 있던
그대로 둘 것입니다. 단순히 각 ProductField
컴포넌트 인스턴스는 자체 상태를 사용하여 모드를
제어할 것입니다: 편집 또는 표시.
따라서 결과적으로, 부모 컴포넌트는 데이터를 담은 상태를 저장하고, 우리의 자손 컴포넌트는 이 데이터를 속성을 통해 받으면서, 자신의 모드를 변경하기 위한 자체 상태를 가지게 될 것입니다.
자, 이제 설명한 것을 구현해 봅시다.
Products 컴포넌트
function Products() {
const [prods, setProds] = useState(initProds);
function changeField(id, field, event) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod[field] = event.target.value;
}
return prod;
}));
}
const rows = prods.map(prod => {
return <Product
key ={prod.id}
id ={prod.id}
name={prod.name}
cost={prod.cost}
catg={prod.catg}
changeField={changeField}
/>;
});
return <div>
<table>
<tbody>
{rows}
</tbody>
</table>
</div>;
}
Product 컴포넌트
function Product({ id, name, cost, catg, changeField }) {
return <tr>
<ProductField id={id} text={name} type="name" changeField={changeField} />
<ProductField id={id} text={cost} type="cost" changeField={changeField} />
<ProductField id={id} text={catg} type="catg" changeField={changeField} />
</tr>;
}
ProductField 컴포넌트
function ProductField({ id, text, type, changeField }) {
const [isEdit, setIsEdit] = useState(false);
return <td>
{
isEdit
? <input
value={text}
onChange={event => changeField(id, type, event)}
onBlur={() => setIsEdit(false)}
/>
: <span onClick={() => setIsEdit(true)}>{text}</span>
}
</td>;
}
실습 과제
이전 강의에서 여러분이 만든 Users와
User 컴포넌트를 가지고 비슷한 작업을
수행해 보세요.