React 입문주차 개인과제 Olympic Medal Tracker(메달 집계 관리 애플리케이션) - 로직구현
vite 프로젝트 생성 후 작업을 시작했다!
<Button>
, <InputField>
, <InputGroup>
, <MedalTable>
4개의 컴포넌트를 제작했다.
<Button>
: 국가 추가, 수정, 삭제를 실행할 버튼을 컴포넌트화 했다.
<InputField>
: 국가, 메달(금, 은, 동) input 또한 컴포넌트화 했다.
<InputGroup>
: <InputField>
, <Button>
을 자식 컴포넌트로 가진 <form>
컴포넌트이다. Creat, Update 로직 등을 구현했다.
처음엔 가장 자식 컴포넌트인 MedalTable에서 로컬스토리지의 데이터가 변경될 때 컴포넌트의 state를 업데이트하는 로직을 넣는건 어떨까 싶었다.
찾아보니 storage event를 사용할 수 있다고 했다!
MDN 문서 - Window: storage event
useEffect(() => {
window.addEventListener('storage', fetchData);
// 컴포넌트 언마운트 시 리스너 제거
return () => {
window.removeEventListener('storage', fetchData);
}, []);
하지만... 전혀 작동하지 않았음.
같은 브라우저 탭 내에서는 사용할 수 없다고 한다. 😔
그리고 최하단 컴포넌트에 localStorage의 값을 불러오면 컴포넌트 간 데이터 공유가 어려워질 것 같았다.
다시 고민한 결과, props는 반드시 위에서 아래로 흐른다 (부모 → 자식)는 것을 감안하여 App 컴포넌트에서 useState를 사용하여 로컬스토리지 데이터를 담고 다른 컴포넌트에 setDataList를 props로 전달하기로 했다.
function App() {
const [dataList, setDataList] = useState([]);
useEffect(() => {
const storedData = JSON.parse(localStorage.getItem("medalList")) || [];
setDataList(storedData);
}, []);
return (
<>
<div className="container">
<h2>2024 파리 올림픽</h2>
<InputGroup setDataList={setDataList} />
<MedalTable dataList={dataList} setDataList={setDataList} />
</div>
</>
);
}
MedalTable에서도 dataList와 setDataList를 props로 받아 사용하였다. dataList의 변경이 감지되면 tbody UI가 자동으로 업데이트 된다.
function MedalTable({ dataList, setDataList }) {
const handleDelete = (index) => {
const updatedDataList = dataList.filter((_, i) => i !== index);
setDataList(updatedDataList);
localStorage.setItem("medalList", JSON.stringify(updatedDataList));
};
...
<tbody>
{dataList.map((data, i) => (
<tr key={i}>
<td>{data.country}</td>
<td>{data.gold}</td>
<td>{data.silver}</td>
<td>{data.bronze}</td>
<td>
<Button text="삭제" onClick={() => handleDelete(i)} />
</td>
</tr>
))}
</tbody>
내일은