인프런 커뮤니티 질문&답변

유승현님의 프로필 이미지

작성한 질문수

풀스택 리액트 토이프로젝트 - REST, GraphQL (for FE개발자)

서버사이드 렌더링

msgs.map is not a function

해결된 질문

21.09.13 22:20 작성

·

802

0

- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요!
- 먼저 유사한 질문이 있었는지 검색해보세요.
- 서로 예의를 지키며 존중하는 문화를 만들어가요.
- 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.
import { useState, useEffect, useRef } from "react";
import { useRouter } from "next/router";
import MsgItem from "./MsgItem";
import MsgInput from "./MsgInput";
import fetcher from "../fetcher";
import useInfiniteScroll from "../hooks/useInfiniteScroll";

const MsgList = (smsgs, users) => {
  const {
    query: { userId = "" },
  } = useRouter();
  const [msgs, setMsgs] = useState(smsgs);
  const [editingId, setEditingId] = useState(null);
  const [hasNext, setHasNext] = useState(true);
  const fetchMoreEl = useRef(null);
  const intersecting = useInfiniteScroll(fetchMoreEl);

  const onCreate = async (text) => {
    const newMsg = await fetcher("post", "/messages", { text, userId });
    if (!newMsg) throw Error("something wrong");
    setMsgs((msgs) => [newMsg, ...msgs]);
  };

  const onUpdate = async (text, id) => {
    const newMsg = await fetcher("put", `/messages/${id}`, { text, userId });
    if (!newMsg) throw Error("something wrong");
    setMsgs((msgs) => {
      const targetIndex = msgs.findIndex((msg) => msg.id === id);
      if (targetIndex < 0) return msgs;
      const newMsgs = [...msgs];
      newMsgs.splice(targetIndex, 1, newMsg);
      return newMsgs;
    });
    doneEdit();
  };

  const onDelete = async (id) => {
    const receivedId = await fetcher("delete", `/messages/${id}`, {
      params: { userId },
    });
    setMsgs((msgs) => {
      const targetIndex = msgs.findIndex((msg) => msg.id === receivedId + "");
      if (targetIndex < 0) return msgs;
      const newMsgs = [...msgs];
      newMsgs.splice(targetIndex, 1);
      return newMsg;
    });
  };

  const doneEdit = () => setEditingId(null);

  const getMessages = async () => {
    const newMsgs = await fetcher("get", "/messages", {
      params: { cursor: msgs[msgs.length - 1]?.id || "" },
    });
    if (newMsgs.length === 0) {
      setHasNext(false);
      return;
    }
    setMsgs((msgs) => [...msgs, ...newMsgs]);
  };

  useEffect(() => {
    if (intersecting && hasNext) getMessages();
  }, [intersecting]);

  return (
    <>
      <MsgInput mutate={onCreate} />
      {userId && <MsgInput mutate={onCreate} />}
      <ul className="messages">
        {msgs.map(x => (
          <MsgItem
            key={x.id}
            {...x}
            onUpdate={onUpdate}
            onDelete={() => onDelete(x.id)}
            startEdit={() => setEditingId(x.id)}
            isEditing={editingId === x.id}
            myId={userId}
            user={users[x.userId]}
          />
        ))}
      </ul>
      <div ref={fetchMoreEl} />
    </>
  );
};

export default MsgList;

 

--------

에러

error - components/MsgList.js (72:14) @ MsgList TypeError: msgs.map is not a function

 

이유가 뭘까요 대체...

답변 1

0

정재남님의 프로필 이미지
정재남
지식공유자

2021. 09. 13. 22:44

msgs.map이 함수가 아니라는 말은, msgs에 map이라는 메서드가 존재하지 않는다는 표현입니다.

그말인 즉 msgs가 정상적인 '배열'이 아니란 뜻이 되죠.

그렇다면 msgs가 어디서부터 정상적인 '배열'이 아니게 되었는지를 추적해보시면 원인을 찾을 수 있을 겁니다.

최초 접근시에 useState(smsgs)에서, smsgs에 들어온 정보를 msgs에 담고 있으니 

smsgs에서부터 제대로된 데이터가 넘어오지 않았다면 여기서 문제가 될 수도 있고,

이후 getMessages 호출에 의해 setMsgs 해주는 부분에서라거나,

혹은 onCreate, onUpdate 등등에서 문제가 될 수도 있으니

제가 위 코드만을 바탕으로 정확한 상황을 모두 파악해서 말씀드리기엔 한계가 있습니다.

 

일단 앞서 말씀드린 순서로 msgs 정보가 제대로 담겨있는지를 먼저 파악해보시고,

그래도 안될 경우엔 댓글 남겨주세요.

유승현님의 프로필 이미지
유승현
질문자

2021. 09. 14. 11:38

smsgs, users 에 {}를 넣으니 수정되었습니다 :)
감사합니다

정재남님의 프로필 이미지
정재남
지식공유자

2021. 09. 14. 11:58

아, 네. 저게 React에서 props를 destructuring한거라서, { }가 없으면 안됩니다.

찾으셔서 다행이네요 :)

const MsgList = (props) => {
  const { smsgs, users } = props;
  ...
}

// =>

const MsgList = ({ smsgs, users }) => { ... }