<< 학습 목표 >>
1. State 끌어올리기를 구현할 수 있다.
Chapter03 에서 프로젝트를 하며 Context 를 사용해 프로젝트 내 컴포넌트들이 데이터를 공유해 사용하는 방법을 배웠음
이번에는 useState 훅을 사용해 인접한 컴포넌트 사이에 데이터를 공유해 사용하는 방법을 배워보자
아래와 같이 부모 컴포넌트는 value 변수를 갖고 있고 value 변수에는 2가 들어있음
자식 컴포넌트 A는 부모 컴포넌트가 갖고 있는 value 변수 값에 2를 곱해 출력하는 컴포넌트
자식 컴포넌트 B는 부모 컴포넌트가 갖고 있는 value 변수 값에 3을 곱해 출력하는 컴포넌트
이런 상황이라면 부모 컴포넌트에서 자식 컴포넌트의 props 로 value 를 전달해 해결할 수 있다는 우리는 걸 잘 알고 있음
이렇게 세 컴포넌트가 하나의 값을 사용하는데 이때 value 변수를 shared state / 공유 변수라고 함
공유 변수라는 말이 붙었지만 전혀 새로울 게 없는 내용임
Chapter03에서 진행했던 주소록 프로젝트에서 주소록을 추가하는 부분만 지금 배운 공유 변수를 적용한 코드로 바꿔보자
Context와 useEffect가 빠진 훨씬 더 가벼운 프로젝트가 됨
코드가 많이 바뀌었으니 프로젝트 -> src -> chapter04 -> AddressMng.jsx 파일을 추가하고 아래 코드를 추가하자
import React, {useState} from 'react';
import AddressAdd from './AddressAdd';
import AddressList from './AddressList';
function AddressMng() {
const [addressInfoList, setAddressInfoList] = useState([]);
function appendAddressInfo(addressInfo) {
let newAddressInfoList = Array.from(addressInfoList);
newAddressInfoList.push(addressInfo);
setAddressInfoList(newAddressInfoList);
}
return(
<div className="container">
<div className="text-center">
<h1>[ 주소록 관리 프로젝트 ]</h1>
<hr />
</div>
<AddressAdd appendAddressInfo={appendAddressInfo} />
<AddressList addressInfoList={addressInfoList}/>
</div>
);
}
export default AddressMng;
<< 코드 설명 >>
(1). 주소록을 저장할 변수 선언
(2). 주소록에 새로운 주소 정보를 추가하는 함수
전에는 useEffect 훅이 주소 정보를 감지하고 있다가 주소 정보가 바뀌었다면 useEffect 안에서 주소록에 새로운 주소 정보를 추가했지만 이제는 이 함수가 그러한 역할을 함
단, 함수이므로 주소 정보를 감지하지는 않음
(3). 주소 정보 추가 컴포넌트로 주소 정보를 추가할 수 있는 함수를 넘김
(4). 주소록 출력 컴포넌트로 주소록을 넘김
프로젝트 -> src -> chapter04 -> AddressAdd.jsx 파일을 추가하고 아래 코드를 추가하자
import React, {useState} from 'react';
function AddressAdd(props) {
const [nameVal, setNameVal] = useState();
const [telVal, setTelVal] = useState();
const [addressVal, setAddressVal] = useState();
const appendAddressInfo = props.appendAddressInfo;
let clickAddBtn = () => {
let addressInfo = {
"name": nameVal,
"tel": telVal,
"address": addressVal,
"rdate": new Date().getTime()
}
appendAddressInfo(addressInfo);
}
return(
<div id="add_panel">
<div className="row align-items-center justify-content-center">
<div className="col-2">
<input type="text" className="form-control" placeholder="이름" onChange={(e) => setNameVal(e.target.value)} />
</div>
<div className="col-2">
<input type="tel" className="form-control" placeholder="연락처" onChange={(e) => setTelVal(e.target.value)} />
</div>
<div className="col-5">
<input type="text" className="form-control" placeholder="주소" onChange={(e) => setAddressVal(e.target.value)} />
</div>
<div className="col-2 text-center">
<button type="button" className="btn btn-primary" onClick={clickAddBtn}>추가</button>
</div>
</div>
<hr />
</div>
);
}
export default AddressAdd;
<< 코드 설명 >>
여기는 바뀐 부분이 크지 않음
(1). 부모 컴포넌트가 전달한 주소록 추가 함수를 꺼냄
(2). 추가 버튼 클릭 시 주소록에 새로운 주소 정보 추가
프로젝트 -> src -> chapter04 -> AddressList.jsx 파일 추가 후 아래 코드 추가
import React from 'react';
import Address from './Address';
function AddressList(props) {
const addressInfoList = props.addressInfoList;
return(
<div id="list_panel">
<table className="table text-center">
<thead>
<tr className="row">
<th className="col-1" scope="col"></th>
<th className="col-2" scope="col">이름</th>
<th className="col-2" scope="col">연락처</th>
<th className="col-5" scope="col">주소</th>
<th className="col-2" scope="col"></th>
</tr>
</thead>
<tbody>
{
addressInfoList.map((addressInfo, index) => {
return <Address
key={addressInfo.rdate+"_"+index}
index={index}
addressInfo={addressInfo}
/>
})
}
</tbody>
</table>
</div>
);
}
export default AddressList
<< 코드 설명 >>
역시 바뀐 부분이 크지 않음
(1). 부모 컴포넌트가 전달한 주소록을 꺼냄
(2). 주소록을 출력
여기서 살짝 달라진게 있다면 주소 정보를 통째로 전달하고 있다는 점
그러나 잘 알고 있듯 전혀 특별하진 않음
프로젝트 -> src -> chapter04 -> Address.jsx 파일 추가 후 아래 코드 추가
import React from 'react';
function Address(props) {
const addressInfo = props.addressInfo;
return(
<tr className="row">
<th className="col-1" scope="row">{props.index+1}</th>
<td className="col-2">{addressInfo.name}</td>
<td className="col-2">{addressInfo.tel}</td>
<td className="col-5 text-left">{addressInfo.address}</td>
<td className="col-2">
<div className="btn-group" role="group" aria-label="Basic example">
<button type="button" className="btn btn-success">수정</button>
<button type="button" className="btn btn-danger">삭제</button>
</div>
</td>
</tr>
);
}
export default Address;
<< 코드 설명 >>
(1). AddressList 부모 컴포넌트가 전달한 주소 정보를 꺼냄
chapter03의 주소록 프로젝트와 여기(chapter04)의 주소록 프로젝트의 차이점은 useEffect 유무
useEffect 훅을 사용해 변수의 변화를 감지할 수도 있지만 useEffect 훅을 사용하지 않아도 변수의 변화를 감지할 수 있음
chapter03에서도 설명했듯이 컴포넌트가 갖고 있는 변수에 변화가 생기면 리엑트는 컴포넌트 내 변수의 값을 바꾸는게 아닌 바뀐 값을 갖고 있는 새로운 컴포넌트를 만들어 교체하기 때문임
여기서 AddressAdd 컴포넌트에서 AddressMng 부모 컴포넌트가 갖고 있는 addressInfoList에 변화를 주는데 이렇게 자식 컴포넌트가 부모 컴포넌트의 변수에 변화를 주는 걸 State 끌어올리기 라고 부름
주소록 수정과 삭제도 State 끌어올리기 를 사용할 수 있으니 그 부분은 여러분이 직접 해보자
'JS + React > React-Chapter04' 카테고리의 다른 글
Chapter04. 리엑트 컴포넌트 합성(Composition) (0) | 2023.04.03 |
---|---|
Chapter04. 리엑트 라우터(Router) (0) | 2023.04.03 |
Chapter04. 리엑트 입력 폼(form) (0) | 2023.04.03 |