안 쓰던 블로그

React-컴포넌트 반복(map()과 key) 본문

Web/React

React-컴포넌트 반복(map()과 key)

proqk 2020. 7. 7. 17:32
반응형

HTML을 보면 반복되는 코드를 작성할 때가 있다

<ul>
 <li>1번</li>
 <li>2번</li>
 <li>3번</li>
</ul>

이런 건 어떻게 효율적으로 바꿀 수 있을까? map()함수를 써봅시다

 

map()

맵은 파라미터로 전달된 함수로 배열 내 각 요소를 프로세싱하고 새로운 배열을 생성한다

 

문법

arr.map(callback, [thisArg])

callback: 새로운 배열의 요소를 생성한다

 -currentValue: 현재 처리하고 있는 요소

 -index: 현재 처리하고 있는 요소의 index값

 -array: 현재 처리하고 있는 원본 배열

thisArg: callback함수 내부에서 사용할 this레퍼런스로 생략 가능하다

 

예제

배열 [1,2,3,4,5]의 각 요소를 제곱해서 새로운 배열을 만드는 예시

var numbers=[1,2,3,4,5];
var processed = numbers.map(function(num){return num*num;});
console.log(processed);

개발자 도구에서 실행시킨 결과

 

같은 내용을 ES6문법으로 작성한 코드

const numbers=[1,2,3,4,5];
const processed = numbers.map(num=>num*num);
console.log(processed);

var이 const가 되고 화살표 함수를 사용한다

 

데이터 배열을 컴포넌트 배열로 map하기

import React, { Component } from 'react';

class IterationSample extends Component {
    render() {
        const names=['봄', '가을', '겨울', '여름'];
        const nameList=names.map((name)=>(<li>{name}</li>));
        return (
            <ul>
                {nameList}
            </ul>                
        );
    }
}

export default IterationSample;

IterationSample.js를 새로 생성하고 위의 코드를 적는다

App.js에서 IterationSample 컴포넌트를 불러와 렌더링한다

 

잘 나오긴 한데, f12를 눌러보면 key가 없다고 한다

key가 뭘까? key에 대해서 알아봅시다

 

key

리액트에서는 컴포넌트 배열을 렌더링했을 때 어떤 원소에 변동이 있었나 보려고 key를 쓴다

key가 없으면 DOM을 비교하는 중에 리스트를 하나씩 보면서 뭐가 바뀌었나 확인한다

key가 있으면 이 과정이 더 효율적으로 바뀐다

 

참고로 key값은 유일해야 한다

유일하지 않으면 렌더링하다가 오류가 날 것임

 

설정

key값은 map한수의 인자로 전달되는 함수 내부에서 컴포넌트 props를 설정하듯이 설정하면 된다

import React, { Component } from 'react';

class IterationSample extends Component {
    render() {
        const names=['봄', '가을', '겨울', '여름'];
        const nameList=names.map((name, index)=>(<li key={index}>{name}</li>));
        return (
            <ul>
                {nameList}
            </ul>                
        );
    }
}

export default IterationSample;

index를 추가해서 key={index}로 key설정을 해주었다

이제 개발자 도구에서 key값이 없다는 에러를 내지 않는다

 

응용

데이터 삽입

import React, { Component } from 'react';

class IterationSample extends Component {
    state={
        names: ['봄', '가을', '겨울', '여름'],
        name: ''
    };
    handleChange=(e)=>{
        this.setState({
            name: e.target.value
        });
    }
    handleInsert=()=>{
        this.setState({
            names: this.state.names.concat(this.state.name),
            name:''
        });
    }
    render() {
        const nameList=this.state.names.map((name, index)=>(<li key={index}>{name}</li>));
        return (
            <div>
                <input
                    onChange={this.handleChange}
                    value={this.state.name}/>
                    <button onClick={this.handleInsert}>추가</button>
                    <ul>{nameList}</ul>
            </div>
        );
    }
}

export default IterationSample;

버튼을 눌러 추가할 수 있다

 

input값은 기본 값 공백 ''이 들어간다

ul위에 input이 들어가게 div로 크게 한 번 감싼다

handleChange와 input은 계속 같으니까 똑같이 해준다

 

중요한 건 handleInsert 메서드 처리방식인데, 기본 자바스크립트처럼 push가 아니라 state는 setState로 접근한다는 점을 기억해야 한다

push는 기존 배열 자체가 변형되므로 옳지 않은 사용이다

그래서 기존 배열을 사용하지 않고, 기존 배열+새 값을 합친 새 배열을 생성하도록 concat을 사용해서 리턴해준다

 

 

데이터 삭제

    handleRemove=(index)=>{
        const{names}=this.state;
        this.setState({
            names:[
                ...names.slice(0,index),
                ...names.slice(index+1, names.length)
            ]
        });
    }

    render() {
        const nameList=this.state.names.map(
            (name, index)=>(
                <li
                    key={index}
                    onDoubleClick={()=>this.handleRemove(index)}>
                    {name}
                </li>
            )
        );

...는 ES6문법 중 전개 연산자 라고 한다

전개 연산자는 ...뒤에 위치한 배열 값을 그대로 꺼내서 현재 배열에 복사하는 일을 한다

 

const numbers=[1,2,3];
const numbers2=[...numbers,4];
//[1,2,3,4]

이렇게 1,2,3을 꺼내서 현재 배열에 복사한 뒤 4를 붙이기 때문에 1,2,3,4가 나오는 식이다

 

그래서 위에 코드처럼 한다면, 일단 첫 번째 ... 때문에 slice로 배열의 0부터 inex까지의 수로 새 배열을 만든다

그리고 index+1부터 끝까지 새 배열을 만든다

이제 둘을 합치면 index만 뺀 새로운 배열이 만들어진다

 

아니면 배열 내장 함수 filter를 사용할 수도 있다

handleRemove=(index)=>{
	const{names}=this.state;
    this.setState({
    	names: names.filter((item,i)=>i!==index)
    });
}

배열에서 특정 조건을 만족하는 값만 추출해서 새로운 배열을 만든다

여기서는 index번째를 제외한 원소만 있는 새 배열을 생성한다

 

아무튼 이제 렌더링하고 나면, 요소를 더블클릭하면 요소가 사라질 것이다

 

 

 

참고한 책: 리액트를 다루는 기술

반응형
Comments