간텔
75
2020-12-28 01:38:04 작성 2020-12-28 10:04:29 수정됨
5
247

리액트 배열 여러항목 수정 질문합니다


index.js 파일인데요

list배열안의 card와 categories배열에 입력에 따라 { id : , kind : }를 추가하려고 합니다.

새로운 데이터를 newData라고 가정할 때

setList(list.card.concat(newData))로 추가하고

다른 컴포넌트에서 list.card.map으로 렌더링하면 map of undefined 에러가 뜨는데 왜 newData를 인식하지 못하는 건가요? 콘솔로 찍어봤을 땐 잘나오는데 이해가 안가네요


이렇게 다른 컴포넌트에서 렌더링 하고 있습니다

0
  • 답변 5

  • 킁킁탐정
    826
    2020-12-28 02:04:16 작성 2020-12-28 02:11:46 수정됨

    에러가 나는 가장 큰 이유는 concat이 반환하는 값 때문에 그렇습니다. 예를 위해 간략하게 줄이겠습니다.

    const list = {
      categories: [1],
      card: [10]

    }

    list.card.concat(20)의 결과값은 list로 정의한 object 모양이 아닌 배열 [10, 20]가 반환됩니다.

    결국 setList([10,20])를 하게되고 이로 인해 에러가 발생하게 됩니다. 해결 방법은 list 형태를 유지해서 setList에 그대로 넘겨주시면 됩니다.



  • 간텔
    75
    2020-12-28 02:31:14

    음... 잘모르겠네요 혹시 예시를 더 들어주실수있나요?


  • 킁킁탐정
    826
    2020-12-28 06:19:09 작성 2020-12-28 06:49:31 수정됨

    가장 간단하게 설명드리면 초기에 list는 object 타입의 변수입니다. 하지만 concat으로 새 데이터를 추가하고 setList를하면 array 타입의 변수가 되어버립니다. 순서대로 나열해보면 다음과 같습니다.


    1. useState로 list에 값을 초기화 할때는 object 타입으로 선언합니다.

    const [list, setList] = useState({
    categories: [
    { id: 1, kind: "식비" },
    { id: 2, kind: "문화" }
    ],
    card: [
    { id: 1, kind: "삼성카드" },
    { id: 2, kind: "국민카드" }
    ]
    });


    2. setList(list.card.concat(newData))를 하면 list는 array 타입으로 변합니다. 결과를 코드로 나타내면 다음과 같습니다.

    const list = [
    { id: 1, kind: "삼성카드" },
    { id: 2, kind: "국민카드" },
    { id: 3, kind: 'NewData'}
    ]


    3. list.card 또는 list.categories는 더이상 유효한 object 프로퍼티가 아니게 됩니다. 결국 null(undefined)이며 null.map() 함수를 호출하려고 해서 정의되지 않았다는 에러를 표시하게 됩니다.

    console.log(list.card == null)
    console.log(list.categories == null)



    4. 동작하는 짧은 코드는 다음과 같습니다.

    import React, { useState } from "react";

    export default function App() {
    const [list, setList] = useState({
    categories: [
    { id: 1, kind: "식비" },
    { id: 2, kind: "문화" }
    ],
    card: [
    { id: 1, kind: "삼성카드" },
    { id: 2, kind: "국민카드" }
    ]
    });

    const insertNewData = () => {
    const newData = {
    id: 3,
    kind: "new kind"
    };
    // Object를 Array로 변환 시킴
    // setList(list.card.concat(newData))

    // 정상 동작하는 코드
    setList({
    ...list,
    card: list.card.concat(newData)
    });
    };
    console.log(list);
    return (
    <div className="App">
    <button type="button" onClick={insertNewData}>
    New data
    </button>
    </div>
    );
    }


  • 페코옹
    1k
    2020-12-28 09:33:22

    위에 킁킁탐정님이 답변 잘 주신거에 조금 추가해서 답변 드립니다.


    import React, { useState } from "react";

    export default function App() {
    const [text, setText] = useState("");
    const [type, setType] = useState("card");
    const [list, setList] = useState({
    categories: [
    { id: 1, kind: "식비" },
    { id: 2, kind: "문화" }
    ],
    card: [
    { id: 1, kind: "삼성카드" },
    { id: 2, kind: "국민카드" }
    ]
    });

    const insertNewData = () => {
    setList((value) => {
    const newId = value[type]
    .map((el) => el.id)
    .sort((a, b) => a - b)
    .pop();
    const newData = {
    id: newId + 1,
    kind: text
    };

    return { ...value, [type]: [...value[type], newData] };
    });
    setText("");
    };

    return (
    <div className="App">
    <input value={text} onChange={(e) => setText(e.target.value)} />
    <br />
    <button
    style={{ backgroundColor: type === "card" && "yellow" }}
    onClick={() => setType("card")}
    >
    카드
    </button>
    <button
    style={{ backgroundColor: type === "categories" && "yellow" }}
    onClick={() => setType("categories")}
    >
    카테고리
    </button>
    <br />
    <button type="button" onClick={insertNewData}>
    New data
    </button>
    <h4>카드</h4>
    <div>
    {list["card"].map((el) => (
    <div>{el.kind}</div>
    ))}
    </div>
    <h4>카테고리</h4>
    <div>
    {list["categories"].map((el) => (
    <div>{el.kind}</div>
    ))}
    </div>
    </div>
    );
    }

  • 간텔
    75
    2020-12-29 21:14:19

    여러사람들의 도움을 얻어 성공했습니다 감사합니다 ㅎㅎㅎ

  • 로그인을 하시면 답변을 등록할 수 있습니다.