map, key


map

mpa 함수를 이용해서 반복되는 내용을 렌더링 할 수 있습니다.

[Arr.js]

import React from "react";


const Arr = () => {

    const names = [1, 2, 3, 4];
    const nameList = names.map(name => <li>{name}</li>)

    return <ul>{nameList}</ul>
};

export default Arr;

위 코드는 names에 있는 값을 하나씩 꺼내서 <li> 태그로 묶어 화면에 표시하는 코드입니다.

python의 map과 비슷하게 동작합니다.

하지만, 브라우저에서 개발자도구에서 확인하면 아래와 같은 에러가 발생합니다.

index.js:1 Warning: Each child in a list should have a unique "key" prop.

Check the render method of `Arr`. See https://fb.me/react-warning-keys for more information.
    in li (at Arr.js:7)
    in Arr (at App.js:8)
    in App (at src/index.js:7)

위 코드에서 map을 사용하는데 있어, key라는 prop이 없다는 에러입니다.

key

key는 어떤 값에 대한 기준점이라 생각하면 됩니다.

[Arr.js]

import React from "react";


const Arr = () => {

    const names = [1, 2, 3, 4];
    const nameList = names.map((name, index) => <li key={index}>{name}</li>)

    return <ul>{nameList}</ul>
};

export default Arr;

map에서는 해당 값과 index를 뽑아낼 수 있습니다. 여기서, index가 기준점이 됩니다.

응용

useState에 각 요소들을 저장하고, 화면에 출력하는 방법은 아래와 같습니다.

[Arr.js]

import React, { useState } from "react";


const Arr = () => {
    const [names] = useState([
        {id: 1, text: ""},
        {id: 2, text: ""},
        {id: 3, text: ""},
        {id: 4, text: ""}
    ]);

    
    const nameList = names.map(name => <li key={name.id}>{name.text}</li>)

    return <ul>{nameList}</ul>

};

export default Arr;

names에는 각 id와 text 총 4개의 요소가 포함되어 있고, map을 이용해 하나씩 추출해 해당 요소의 idtext를 화면에 출력하게 됩니다.

요소 추가하기

기존에 선언된 데이터 외에 input 태그를 이용하여 값을 받아 추가하는 방법에 대해 알아보겠습니다.

[App.js]

import React, { useState, Fragment } from "react";


const Arr = () => {
    const [names, setNames] = useState([
        {id: 1, text: ""},
        {id: 2, text: ""},
        {id: 3, text: ""},
        {id: 4, text: ""}
    ]);
    const [inputText, setInputText] = useState();
    const [nextId, setNextId] = useState(5);
    
    const onChange = (e) => setInputText(e.target.value);
    const onClick = (e) => {
        const nextNames = names.concat({
            id: nextId,
            text: inputText
        });

        setNextId(nextId + 1);
        setNames(nextNames);
        setInputText("");
    };


    const nameList = names.map(name => <li key={name.id}>{name.text}</li>)

    return (
        <Fragment>
            <input value={inputText} onChange={onChange}></input>
            <button onClick={onClick}>추가</button>
            <ul>{nameList}</ul>
        </Fragment>
    );

};

export default Arr;

위 코드를 작성하여 실행하면 정상적으로 input 태그의 내용이 추가됩니다. 하지만 콘솔을 확인해 보면 아래와 같은 에러가 발생합니다.

Warning: A component is changing an uncontrolled input of type undefined to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://fb.me/react-controlled-components
    in input (at Arr.js:31)
    in Arr (at App.js:8)
    in App (at src/index.js:7)

공식문서에 의하면 input, textarea, select와 같은 엘리먼트는 state를 관리하고 업데이트 한다 합니다.

새로 추가되는 내용 때문에 에러가 발생하는 것 같습니다.

요소 삭제하기

import React, { useState, Fragment } from "react";


const Arr = () => {
    const [names, setNames] = useState([
        {id: 1, text: ""},
        {id: 2, text: ""},
        {id: 3, text: ""},
        {id: 4, text: ""}
    ]);
    const [inputText, setInputText] = useState();
    const [nextId, setNextId] = useState(5);
    
    const onChange = (e) => setInputText(e.target.value);
    const onClick = (e) => {
        const nextNames = names.concat({
            id: nextId,
            text: inputText
        });

        setNextId(nextId + 1);
        setNames(nextNames);
        setInputText("");
    };

    const onRemove = (id) => {
        const nextNames = names.filter(name => name.id !== id);
        setNames(nextNames);
    }

    const nameList = names.map(name => <li key={name.id} onDoubleClick={() => onRemove(name.id)}>{name.text}</li>)

    return (
        <Fragment>
            <input value={inputText} onChange={onChange}></input>
            <button onClick={onClick}>추가</button>
            <ul>{nameList}</ul>
        </Fragment>
    );

};

export default Arr;

더블클릭 시 삭제하고 싶은 경우 onDoubleClick을 이용하고, onRemove 함수를 만들어서 filter 함수를 이용하여 해당 내용을 삭제하고 갱신해주면 됩니다.




© 2017. by k3y6reak

Powered by k3y6reak