다음과 같이 사용자가 데이터를 입력 후, 저장 버튼을 누르면 리스트에 append 되는 기능을 구현 할 때 필요한 로직에 대해서 기록하고자 합니다.
현재 수행하고 있는 프로젝트는 다음과 같은 구조를 지니고 있습니다.
App.js
: 부모 컴포넌트
DiaryEditor.js
: 사용자가 일기를 입력하는 컴포넌트
DiaryList.js
: 여러개의 일기를 List로 부모 컴포넌트 App.js
에 렌더링 하는 컴포넌트
🤔 사용자 입력을 받아 리스트로 렌더링하여 부모 컴포넌트에 그려준다.
해당 부분을 구현하기 위해 생각이 드는 방향성은 DiaryEditor
에서 작성한 현재 상태값 state
를 DiaryList
에 넘겨서 App
에 그리면 되는거 아닐까? 하는 생각이 들 수 있다.
결론은 불가하다.
즉 리액트는 같은 level에 있는 컴포넌트끼리는 데이터를 주고 받을 수 없는 단방향성의 흐름을 지니고 있다.
그러면 어떤 방안이 있을까 생각해보면 다음과 같이 다시 구조화 할 수 있다.
오직 부모에서 자식으로 데이터를 보내는 단방향성의 흐름을 지니고 있는 리액트의 특징을 살려, App.js
에서 useState를 활용하여 주고 받을 수 있다.
즉, 입력에 따라 상태를
변화시켜주는 setData
는 DiaryEditor
로 넘겨서 새로운 일기를 작성하고
그리고 setting된 값을 data가 DiaryList
의 props로 넘겨지는 구조이다.
그렇게 되면 위와 같은 흐름으로 사용자 입력에 따른 데이터와 이벤트 흐름의 구조가 이뤄진다. 리액트에서는 주로 이벤트는 역방향으로 데이터는 순방향으로 흐른다고 한다.
이는 곧 State 끌어올리기 라고 한다.
실제 코드로 살펴보며 어떻게 데이터와 이벤트가 driven 되는지 알아보자.
App.js
파일const App = () => {
const [data,setData] = useState([]); //현재 state인 data를 diaryList로 넘기고, 상태변화는 Editor에서 props로 넘겨져 이뤄진다.
const dataId = useRef(0); //id를 리스트에 넘겨줘야 함
const onCreate = (author,content,emotion) => {
const created_date = new Date().getTime();
const newItem = {
author,
content,
emotion,
created_date,
id: dataId.current
}
dataId.current += 1;
setData([newItem,...data]); //newItem이 맨 위에 추가되도록 setData 매개변수로 전달
};
return (
<div className="App">
<DiaryEditor onCreate={onCreate}/> {/* 일기 작성 건들을 prop으로 넘겨줌 */}
<DiaryList diaryList={data}/>
</div>
);
}
onCreate
함수는 사용자가 입력을 할때 상태값 data
를 변화시켜주는 setData
를 DiaryEditor
에 props로 넘겨주는 기능을 수행한다.
그리고 상태값 data
는 리스트를 렌더링하는 DiaryList
의 props로 넘겨진다.
DiaryEditor.js
- props 처리하는 부분const DiaryEditor = ({onCreate}) => {
const [state,setState] = useState({
author: "",
content: "",
emotion: 1,
}); //작성자, 일기장 쓰는 state로직이 동일하므로 하나의 state로 관리
/**
* 일기 저장하기 버튼을 수행합니다.
*/
const handleSubmit = () => {
// 입력 validation check
if(state.author.length < 1){
authorInput.current.focus();
return;
}
if(state.content.length < 5){
contentInput.current.focus();
return;
}
onCreate(state.author,state.content,state.emotion);
alert('저장 성공');
}
};
onCreate
를 props로 전달 받게 되고, 저장을 할때 리스트 렌더링이 필요하기 때문에 onCreate
props를 handleSubmit()
에서 호출하게 됩니다.
그러면 이렇게 다시 생각할 수 있습니다.
DiaryEditor.js
에서 저장버튼 클릭 시, 호출한 onCreate
를 부모 컴포넌트 App.js
에 넘긴다.newItem
객체 담은 후, setData
로 현재 상태값인 data
의 값을 변화시킨다. 지금까지 State 끌어올리기를 통해 컴포넌트 간 데이터를 주고 받는 과정을 살펴 보았습니다.