[React] map( )을 이용한 배열 렌더링 (feat.일기장)

Hyun·2022년 1월 4일
5

React

목록 보기
6/22
post-thumbnail

💡map() 이란?

  • 자바스크립트 배열 내장함수
  • 리액트에서 동적인 배열을 렌더링해야 할 때는 자바스크립트 배열 내장함수인 map()을 사용하여 일반 데이터 배열을 리액트 엘리먼트로 이루어진 배열로 변환해줍니다.

    map() 함수는 배열안에 있는 각 원소를 변환할때 원소들을 이용하여 새로운 배열을 만들어줍니다.

렌더링이란? = 간단하게 말하자면 화면에 나타낸다


📖예제

배열을 이용하여 React에서 List렌더링을 해보고 개별적인 컴포넌트로 만들어보기
실제로 리액트에서 배열은 게시글, 리스트, 피드를 표시하는데에 자주사용된다.

먼저 일기리스트컴퍼넌트를 작성할 DiaryList.js파일을 만들어준다.

1. DiaryList.js

const DiaryList=()=>{
    return <div className="DiaryList">
      <h2>일기리스트<h2>
    </div>
}

export default DiaryList;

일단 들어가기전에, 임시배열(dummyList)을 만들어서 DiaryList에 prop으로 데이터를 전달한 후 그 데이터를 리스트 렌더링하는것부터 연습해보자

2. App.js

import './App.css';
import DiaryEditor from "./DiaryEditor";
import DiaryList from "./DiaryList"

const dummyList = [
  {
    id: 1,
    author: "hyun",
    content: "첫번째",
    emotion: 1,
    created_date: new Date().getTime()
  },
  {
    id: 2,
    author: "jeong",
    content: "두번째",
    emotion: 2,
    created_date: new Date().getTime()
  },
  {
    id: 3,
    author: "react",
    content: "3번째",
    emotion: 3,
    created_date: new Date().getTime()
  }
]

const App = () => {
  return (
    <div className="App">
      <DiaryEditor/>
      <DiaryList diaryList={dummyList}/>
    </div>
  );
}

export default App;

시간객체에 생성자를 아무것도안넣고 new Date()생성하면, 시간은 현재시간을 기준으로 생성이된다.
Date객체에 getTime이라는 매서드를사용해서 초로 나타내도록 하였다.(Gets the time value in milliseconds.)

const DiaryList=({diaryList})=>{
    return (
    <div className="DiaryList">
        <h2>일기리스트</h2>
        <h4>{diaryList.length}개의 일기가 있습니다.</h4>
        <div>
            {diaryList.map((it)=>(
                <div>
                    <div>작성자: {it.author}</div>
                    <div>내용: {it.content}</div>
                    <div>감정: {it.emotion}</div>
                    <div>작성시간(ms): {it.created_date}</div>
                </div>
            ))}
        </div>
    </div>
    );
};

export default DiaryList;

it은 diaryList배열의 하나하나의요소가 들어오는거라 하나의 객체가 id이 된다.(객체 점표기법으로 접근할 수 있다.)

배열의 요소를 리스트형태로 렌더링된것을 확인할 수 있다.


👉🏻defaultProps사용하는 방법

근데 App.js에서 <DiaryList diaryList={dummyList}/>로 props값을 전해줘야하는데, <DiaryList diaryList={undefined}/>로 주었다면?

->undefined으로부터 length라는 프로퍼티를 읽어올수가없다는 라는 에러가 나온다
-> 이럴땐, 저번에 배운 defaultProps를 사용하면 된다!!

defaultProps
= undefined으로 전달될거같은 props들의 기본값(=초기값)을 설정해주는 기능

📖예제

1. App.js

import './App.css';
import DiaryEditor from "./DiaryEditor";
import DiaryList from "./DiaryList"


const dummyList = [
  {
    id: 1,
    author: "hyun",
    content: "첫번째",
    emotion: 1,
    created_date: new Date().getTime()
  },
  {
    id: 2,
    author: "jeong",
    content: "두번째",
    emotion: 2,
    created_date: new Date().getTime()
  },
  {
    id: 3,
    author: "react",
    content: "3번째",
    emotion: 3,
    created_date: new Date().getTime()
  }
]
const App = () => {
  return (
    <div className="App">
      <DiaryEditor/>
      <DiaryList diaryList={undefined}/>
      //원래 dummyList로전달되어야하는데, undefined로 전달한상태
    </div>
  );
}

export default App;

2. DiaryList.js

const DiaryList=({diaryList})=>{
    return (
    <div className="DiaryList">
        <h2>일기리스트</h2>
        <h4>{diaryList.length}개의 일기가 있습니다.</h4>
        <div>
            {diaryList.map((it)=>(
                <div>
                    <div>작성자: {it.author}</div>
                    <div>내용: {it.content}</div>
                    <div>감정: {it.emotion}</div>
                    <div>작성시간(ms): {it.created_date}</div>
                </div>
            ))}
        </div>
    </div>
    );
};

DiaryList.defaultProps={
    diaryList:[], 
};
//defaultProps로 초기값을 빈배열로 설정해줌
export default DiaryList;


👉🏻map()에서 Key가 필요한 이유

다시 props에 dummyList 값을 넣어줘서 콘솔을 확인하면 아래와같은 에러가 뜨는것을 확인할수있다.

dummyList에 만든 3개의 리스트들 안에 있는 자식요소들(id,author,content,emotion,created_date)은 반드시 고유한 key라는 prop을 받아야 한다 라는 에러이다

<div ket={it.id}>
	<div>작성자: {it.author}</div>
	<div>내용: {it.content}</div>
	<div>감정: {it.emotion}</div>
	<div>작성시간(ms): {it.created_date}</div>
</div>

지금사용하는 고유한값인 id를이용하여 key를 주었다.

{diaryList.map((it,idx)=>(
  <div ket={idx}>
      <div>작성자: {it.author}</div>
      <div>내용: {it.content}</div>
      <div>감정: {it.emotion}</div>
      <div>작성시간(ms): {it.created_date}</div>
  </div>
 ))}

만약 배열의 원소에 고유한값이 없을 경우에는, map내장함수의 콜백함수에 두번째 파라미터에 idx를 key로 사용하는 방법이 있다.
(*index란? 몇번째요소를순회하고있는지를알려주는값)
배열 요소들의 인덱스는 고유하므로 키로 사용해도 일단 문제가 사라진다.
하지만 배열의 인덱스를 사용하게되면, 데이터를 수정,삭제,추가해서 인덱스의 순서가 바뀌어버릴때 리액트에서 문제가 생길 수 있다.
그래서, 고유한 id를 갖고있으면 인덱스(idx)를 사용하지말고 고유한 id로 key를 지정하는게 가장 좋다

🎯map()에서 Key정리

  • Map에 key값이 없다면 중간의 값이 바뀌었을때 그 하위 값들이 전부 변하기 때문인다. key값을 사용한다면 key를 이용해 중간의 값을 추가하게 된다.
  • 고유 원소에 key 가 있어야만 배열이 업데이트 될 때 효율적으로 렌더링
  • 수정되지 않는 기존의 값은 그대로 두고 원하는 곳에 내용을 삽입하거나 삭제하기 때문
  • 만약에 배열안에 중복되는 key 가 있을 때에는 렌더링시에 오류메시지가 콘솔에 나타나게 되며, 업데이트가 제대로 이루어지지 않게 된다.

배열을 DiaryItem으로 분할하기

diaryList배열에서 map메서드를 통하여 리스트아이템들을 화면에 렌더링을 하고있는데, 프로그램에서 일기아이템들을 삭제,수정하는 기능들도 넣고싶다.
원래는 DiaryList컴포넌트는 리스트를 렌더링하려고 컴포넌트를 만들었는데, 삭제,수정하는 기능들까지넣으면 매우 안좋아진다.(=컴포넌트의 고유기능을 잃는느낌)
그래서 diaryList배열을 사용해서 렌더하는 아이템(작성자,일기,감정,시간)을 별도의 컴포넌트인 DiaryItem으로 분할한다.

//DiaryList.js
import DiaryItem from "./DiaryItem.js"

const DiaryList=({diaryList})=>{
    return (
    <div className="DiaryList">
        <h2>일기리스트</h2>
        <h4>{diaryList.length}개의 일기가 있습니다.</h4>
        <div>
            {diaryList.map((it)=>(
                <DiaryItem key={it.id} {...it} />
            ))}
        </div>
    </div>
    );
};

export default DiaryList;

DiaryItem은 일기데이터들을 렌더링을해야하기때문에(=리스트아이템이기때문에) key={it.id}를 주었다.
또, 일기 하나 객체에 포함된 모든 데이터를 스프레드연산자를 통해서 전달해주었다. 그러면 it이라는 객체에 포함된 모든데이터가 DiaryItem에게 prop으로 전달된다.

//DiaryItem.js
const DiaryItem = ({author, content, created_date, emotion, id}) => {
    return <div className="DiaryItem">
        <div className="info">
            <span>
                작 성 자 : {author} | 감 정 점 수 : {emotion}
            </span>
            <br />
            <span className="date">
                시 간 : {new Date(created_date).toLocaleString()}
            </span>
            <div className="content">
                내 용 : {content}
            </div>
        </div>
    </div>
};

export default DiaryItem;

리스트렌더링이 끝났다.
간단한 css으로 마무리를 해주고 다음공부기록을 이어갈 예정이다👩🏻‍💻

//App.css
/* List */
.DiaryList {
  border: 1px solid gray;
  padding: 20px;
  margin-top: 20px;
}

.DiaryList h2 {
  text-align: center;
}

/* Item */
.DiaryItem {
  background-color: rgb(240, 240, 240);
  margin-bottom: 10px;
  padding: 20px;
}

.DiaryItem .info {
  border-bottom: 1px solid gray;
  padding-bottom: 10px;
  margin-bottom: 10px;
}

.DiaryItem .date {
  color: gray;
}

.DiaryItem .content {
  font-weight: bold;
  margin-bottom: 30px;
  margin-top: 30px;
}

🚀참고자료

배열 렌더링하기
React강의-이정환강사

profile
FrontEnd Developer (with 구글신)

0개의 댓글