먼저 list 배열을 props로 넘겨서 DiaryList.js에서 그 데이터로 렌더링을 해보도록 하겠습니다.
App.js
import './App.css';
import DiaryEditor from './DiaryEditor';
import DiaryList from './DiaryList';
const dummyList = [
{
id:1,
name: 'jay',
content: 'hi 1',
hungry: 10,
created_date: new Date().getTime()
},
{
id:2,
name: 'jay2',
content: 'hi 2',
hungry: 20,
created_date: new Date().getTime()
},
{
id:3,
name: 'jay3',
content: 'hi 3',
hungry: 10,
created_date: new Date().getTime()
},
{
id:4,
name: 'jay4',
content: 'hi 4',
hungry: 40,
created_date: new Date().getTime()
},
]
function App() {
return (
<div className="App">
<DiaryEditor/>
<DiaryList diaryList={dummyList}/>
</div>
);
}
export default App;
DiaryList.js
const DiaryList = ({ diaryList }) => {
console.log(diaryList)
return (
<div className="DiaryList">
<h2>일기 리스트</h2>
</div>
);
};
export default DiaryList;
props로 데이터를 잘 넘긴 것을 확인할 수 있습니다.
DiaryList.js
const DiaryList = ({ diaryList }) => {
return (
<div className="DiaryList">
<h2>일기 리스트</h2>
<h4>{diaryList.length}개의 일기가 존재합니다.</h4>
<div>
{diaryList.map((it) => (
<div>
<div>작성자 : {it.name}</div>
<div>내용 : {it.content}</div>
<div>배고픔 정도 : {it.hungry}</div>
<div>작성 시간 : {it.created_date}ms</div>
</div>
))}
</div>
</div>
);
};
export default DiaryList;
매개변수로 diaryList를 받고 그 값을 map 함수를 사용하여 각 데이터에 접근이 가능합니다. 세부적인 데이터 접근은 점 표기법을 사용하여 ui에 나타내보았습니다.
매개변수로 받은 diaryList가 undefined 일 수 있기 때문에 defaultProps를 사용해서 에러를 방지하도록 하겠습니다.
const DiaryList = ({ diaryList }) => {
return (
<div className="DiaryList">
<h2>일기 리스트</h2>
<h4>{diaryList.length}개의 일기가 존재합니다.</h4>
<div>
{diaryList.map((it) => (
<div>
<div>작성자 : {it.name}</div>
<div>내용 : {it.content}</div>
<div>배고픔 정도 : {it.hungry}</div>
<div>작성 시간 : {it.created_date}ms</div>
</div>
))}
</div>
</div>
);
};
DiaryList.defaultProps = {
diaryList: [],
};
export default DiaryList;
props로 undifined를 넘겨도 에러가 발생하지 않는 것을 확인할 수 있습니다.
하지만 콘솔에 에러가 찍혀있는 것을 확인할 수 있습니다. "자식 컴포넌트가 key prop를 받아야 한다는 것입니다."
더미 데이터의 고유 id인 id로 자식 아이템의 최상위 태그에 key를 설정해주면 됩니다.
DiaryList.js
const DiaryList = ({ diaryList }) => {
return (
<div className="DiaryList">
<h2>일기 리스트</h2>
<h4>{diaryList.length}개의 일기가 존재합니다.</h4>
<div>
{diaryList.map((it) => (
<div key={it.id}>
<div>작성자 : {it.name}</div>
<div>내용 : {it.content}</div>
<div>배고픔 정도 : {it.hungry}</div>
<div>작성 시간 : {it.created_date}ms</div>
</div>
))}
</div>
</div>
);
};
DiaryList.defaultProps = {
diaryList: [],
};
export default DiaryList;
콘솔에 에러가 사라진 것을 확인할 수 있습니다.
만약 넘겨진 props의 고유한 id가 없다면 ?? 아래 방법을 사용하면 됩니다.
<div>
{diaryList.map((it, idx) => (
<div key={idx}>
<div>작성자 : {it.name}</div>
<div>내용 : {it.content}</div>
<div>배고픔 정도 : {it.hungry}</div>
<div>작성 시간 : {it.created_date}ms</div>
</div>
))}
</div>
몇번째 요소를 순회하고 있는지를 나타내는 idx를 사용하여 key 설정이 가능합니다.
하지만 이것은 배열의 순서를 나타내는 것이기 때문에 react에서 삭제, 추가 등의 작업을 하는 과정에서 문제가 생길 수 있습니다. 고유한 아이디를 가지고 idx를 사용하지 않는 것을 권장합니다.
현재는 diaryList에 map을 사용하여 리스트 아이템들을 렌더링하고 있습니다. 목표는 일기 프로젝트를 삭제, 수정도 가능해야 합니다. 그 기능들이 DiaryList.js에 추가된다면 너무 많은 기능이 DiaryList.js에 들어가게 되는 것입니다. 이것은 좋지 않은 방법이므로 diaryList 배열 데이터를 렌더링하는 item을 별도로 분할하도록 하겠습니다.
DiaryList.js
import DiaryItem from "./DiaryItem";
const DiaryList = ({ diaryList }) => {
return (
<div className="DiaryList">
<h2>일기 리스트</h2>
<h4>{diaryList.length}개의 일기가 존재합니다.</h4>
<div>
{diaryList.map((it) => (
<DiaryItem key={it.id} {...it} />
))}
</div>
</div>
);
};
DiaryList.defaultProps = {
diaryList: [],
};
export default DiaryList;
DiaryList에서 key로 id를 , 그리고 나머지를 스프레드 연산자로 props를 넘겨주었습니다.
DiaryItem.js
const DiaryItem = ({ name, content, created_date, hungry, id }) => {
return (
<div className="DiaryItem">
<div className="info">
<span>
이름 : {name} | 배고픔 정도 : {hungry}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">{content}</div>
</div>
);
};
export default DiaryItem;
비구조화 할당으로 받은 데이터를 보여주는 코드입니다.
<span className="date">{new Date(created_date).toLocaleString()}</span>
created_date는 ms로 받았기 때문에 사람이 읽을 수 있는 형식으로 바꿔주었습니다.
css를 추가하고
App.css
.DiaryEditor {
border: 1px solid blueviolet;
text-align: center;
padding: 20px;
}
.DiaryEditor input,
textarea {
margin-bottom: 20px;
width: 500px;
padding: 10px;
}
.DiaryEditor textarea {
height: 150px;
}
.DiaryEditor select {
width: 60px;
padding: 10px;
margin-bottom: 20px;
margin-left: 30px;
}
.DiaryEditor button {
width: 500px;
height: 50px;
cursor: pointer;
background-color: blueviolet;
}
/* List */
.DiaryList {
border: 1px solid blueviolet;
padding: 20px;
margin-top: 20px;
}
.DiaryList h2 {
text-align: center;
}
/* item */
.DiaryItem {
background-color: lightskyblue;
margin-bottom: 10px;
padding: 20px;
}
.DiaryItem .info {
border-bottom: 1px solid blue;
padding-bottom: 10px;
margin-bottom: 10px;
}
.DiaryItem .date {
color: gray;
}
.DiaryItem .content {
font-weight: bold;
margin-bottom: 30px;
margin-top: 30px;
}
css도 잘 적용 된 것을 확인할 수 있습니다. 다크모드를 사용하니 css가 잘 안보여서 마지막 캡쳐는 다크모드를 풀고 캡쳐했습니다.
해당 게시글은 인프런 강의
"한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지(이정환)"
를 정리한 내용입니다. 쉽게 잘 설명해주시니 여러분도 강의를 듣는 것을 추천드립니다.