가장 먼저 생각 해봐야 할 것이 있다. 어떤 방향으로 데이터를 주고 받을 것 인지
가장 상위의 App
그 하위에 리스트를 보여주는 DataList
,
DataList
를 추가 삭제할 수 있는 DataEditor
이렇게 트리 형태로 구조가 형성 되어있다.
그러나 리액트에서는 같은 레벨에 있는 컴포넌트끼리는 데이터를 주고 받지 못한다.
같은 레벨끼리는 데이터를 주고 받을 수 없다!
그럼 어떻게 데이터를 주고 받고 추가 삭제 할 수 있어?
글로 이해를 하려고 하니 어려운 부분이 있어 그림으로 알아보자
DataEditor
와 DataList
의 공통 부모인 App
가 State
로 관리를 한다.
이게 무슨 말이지?
DataList
에서는 부모인 App
에게 Data
를 받아 화면에 렌더링을 해주는 역할
DataEditor
에서는 Data라는 State
를 변경할 수 있는 setData
를 통해 변경 해주는 역할
정리를 해보자면
State
는 배열이며, [item1] 을 가지고 있다고 가정하자DataList
는Data
에서 받은 item1을prop
로 받아 화면에 렌더링 하고 있는 상태DataEditor
에서 [item2]를 추가를 하면setData
를 통해Data
의 값을 바꾸게 된다.- 그렇게 되면
State
에는 [item1, item2]가 생기게 된다.DataList
에는 새로운 데이터가prop
되고 두개의 아이템이 화면에 렌더링되게 된다.
데이터를 수정하는 EVENT는 밑에서 위로, 수정된 데이터를 전달받는 DATA는 위에서 밑으로
그럼 이제 코드를 작성해보러 가자
import { useState } from 'react';
function App () {
const [data,setData] = useState([])
return(
<div className="App">
<DataEditor/>
<DataList dataList={data}/>
</div>
)
}
data를 받아 화면에 렌더링 될 준비가 된 DataList
위의 코드에서 data
를 변경 시켜줄 setData
함수를 추가해보자
import { useState, useRef } from 'react';
import './App.css';
import DataEditor from './DataEditor';
import DataList from './DataList';
function App() {
const subject = ['국어', '수학', '영어', '과학탐구', '사회탐구'];
const [data, setData] = useState([]);
const dataId = useRef(0);
const onCreate = (name, content, score) => {
const newItem = {
name,
content,
score,
id: dataId.current,
};
dataId.current += 1;
setData([newItem, ...data]);
};
return (
<div className="App">
<div className="TitleArea">
<h2>커리큘럼</h2>
<ul className="SubjectLuist">
{subject.map((it, idx) => (
<li key={idx}>{it}</li>
))}
</ul>
</div>
<DataEditor onCreate={onCreate} />
<DataList dataList={data} />
</div>
);
}
export default App;
dataId
- 0값을 참조하는데 newItem을 만들 때 마다 +1씩 증가onCreate
- DataEditor
에서 호출한 함수 + 상위 컴포넌트에 새로운 데이터 전달리액트에서는 상위 컴포넌트에서 데이터를 관리, 하위 컴포넌트에 필요한 데이터를 prop로 전달하는 패턴을 가진다.
전 장에서는 버튼을 눌렀을 때 조건을 걸고 맞지 않으면 focus
되고 맞으면 state
를 콘솔에 저장까지 해보았다.
const DataEditor = () => {
const handleSubmit = () => {
onCreate(state.name, state.content, state.score);
};
};
handleSubmit
함수를 통해state.name
,state.content
,state.score
을onCreate
의 전달 하게 끔 하는 역할을 한다.
const DataList = ({ dataList }) => {
return (
<div className="DataList">
<div>
{dataList.map((it) => (
<DataItem key={it.id} {...it} />
))}
</div>
</div>
);
};
dataList
를 prop으로 받아 key 값은it.id
...it
을 통해 해당 요소의 속성을DataItem
에 전달
const DataItem = ({id, name, content, score}) => {
return (
<div className="DataItem">
<h2>{id}. {name}</h2>
<p>{content}</p>
<p>{score}</p>
</div>
)
}
export default DataItem;
데이터를 삭제하기 위해선 해당 데이터가 고유한 값을 가지고 있어야 해당 데이터에 접근을 해서 삭제, 수정이 가능하다. 그렇기에 ID에 접근해 해당 데이터를 삭제해보자
각각의 ID에 접근하여 Data를 수정하여 setData에 반영을 해보기 위해
onDelete
함수를 prop해준다.
const onDelete = (targetId) => {
const newDataList = data.filter((it) => it.id !== targetId);
setData(newDataList);
};
{/* 생략 */}
<DataList onDelete={onDelete}/>
현재 상태의 data
는 추가된 Item을 모두 보여주는 상태이기에
해당 ID를 가진 Item을 제외한 상태를 다시 setData
를 통해 상태를 업데이트 시켜준다.
const DataList = ({ dataList, onDelete }) => {
<DataItem onDelete={onDelete}/>
}
DataItem
은 DataList
에 포함이 되어 있기에 DataList
가 받은 onDelete
를 다시 DataItem
에게 prop
const DataItem = ({ id, name, content, score, onDelete }) => {
<button
onClick={() => {
console.log(id); // id가 잘 출력이 되기에
onDelete(id); // 해당 id 삭제
}}
>
삭제하기
</button>;
};
이렇게 추가, 삭제하는 것을 알아 보았는데 아직 갈길이 멉니다
다음에는 해당 데이터를 수정해보는 것을 배워오겠습니다.