[Error] useState Array에서 splice 렌더링 에러

이명진·2024년 1월 25일
0

겪은에러모음집

목록 보기
2/4

에러 정의

next js 12 버전을 사용하고 있는 와중에
array를 렌더링 하는데 array 다음 으로 배열을 추가할때 렌더링 에러가 발생하게 되었다.

array를 뿌린것에 대해서 중간에 "추가" 버튼을 누르면 array click index에 값이 추가 되고 나머지 값들은 뒤로 밀린다.

splice를 이용하여서 구현을 하였는데 배열 결과값은 잘 바뀌었는데 렌더링이 문제가 있었다.

ADD 노란색이 추가하는 버튼이다.
첫번째 ADD버튼을 누르면 그 아래단계에서 추가가 되야 하는데 하단에 새롭게 렌더링이 되는 문제였다.

위에는 객체를 찍어봤는데 콘솔과 렌더링 객체는 정확한 값으로 찍혔다.

어디 렌더링에서 오류가 생기는것이 아닌지 콘솔을 다찍어봤었는데 다 정상으로 나와서 환장할 노릇이었다.

코드를 첨부할수가 없어서 간략하게 코드 구성을 정리해보면 이렇다.

부모 컴포넌트에 array를 관리하고 props로 array 를 전달해준다. 또한 부모에서 추가 함수를 만들어서 props로 함수를 내려줘서 클릭할때 이 함수를 실행하게 한다.

// 대략 부모 코드 
 const [contents, setContents] = useState<contentsListType[] | undefined>(
    contentsLists || undefined
  );
  //추가 하는 함수  seq로 클릭시 클릭한 seq를 받는다. 
  const onAddList = (seq: number) => {
    setContents(prev => {
      if (prev) {
        const newList: contentsListType = {
          conferenceDetailTypeNo: 1,
          contents: '신규',
        const copyPrev = [...prev];
        copyPrev.splice(seq + 1, 0, newList);
        return copyPrev;
      }
      return prev;
    });
  };
  // 렌더링 측 map함수 
  {contents &&
        contents.map((item, idx) => {
          return (
            <AddLists
              seq={idx}
              contentsObj={item}
              setContents={setContents}
              conferenceDetailTypeList={conferenceDetailTypeList}
              onAddList={onAddList}
              key={`item-${idx}`}
            />
          );
        })}
  

이런식으로 부모 코드는 설계가 되어 있다.

contents array를 자식에게서 받는 click seq로 splice로 배열을 수정해서 다시 뿌려주는 것이다.

//자식 코드 일부 
  const [textValue, setTextValue] = useState(contents || '');
  // props로 contents를 받는다. 

//렌더링측 코드 

//클릭시 전달받은 seq를 전달해줌 
 <div
        style={{ ...titleStyle, textAlign: 'center' }}
        onClick={() => onAddList(seq)}
      >
        ADD
      </div>
      
      // 뿌리는 부분 
       <Box display={'flex'}>
            <textarea
              style={{ marginLeft: '1rem', width: '80%' }}
              value={textValue}
            />
            {buttonSet()}
          </Box>

console.log로 값들도 다 확인해봤는데 값들은 배열 그대로 잘 전달 받았다.
다만 이상한게 textValue로 props받은것을 씌워주었는데
contents는 수정된 결과였지만 textValue는 이상한 값을 가지고 있었다

결과 스샷을 봐도 맨 마지막이 추가 된 것인데 이전의 값을 가지고 있는 것이 보인다

왜 이런건지 검색을 해봐도 잘 안나와서 환장할 노릇이었다...
어디가 문제인지 몰라서 많이 헤매면서 시간을 소요했는데 해결은 이상하리 만큼 쉽게 되었다.

해결

중간에 추가한 값을 서버에 저장하기 위해서 10000단위로 orderNo를 정하고 중간에 추가하면 앞의 orderNo + 클릭한 orderNo /2 로 추가를 해줬다.

이 값이 unique 하기 때문에 map함수 내의 key값을 이값으로 수정해주었다.

원래는 index로 array index값을 key로 가지고 있었는데

const onAddList = (seq: number) => {
    setContents(prev => {
      if (prev) {
        const newList: contentsListType = {
          conferenceDetailTypeNo: 1,
          contents: '신규',
          orderNo:
            seq + 1 === prev.length
              ? prev[prev.length - 1].orderNo + 10000
              : (prev[seq].orderNo + prev[seq + 1].orderNo) / 2,
        };
        const copyPrev = [...prev];
        copyPrev.splice(seq + 1, 0, newList);
        return copyPrev;
      }
      return prev;
    });
  };
 {contents &&
        contents.map((item, idx) => {
          return (
            <AddLists
              seq={idx}
              contentsObj={item}
              setContents={setContents}
              conferenceDetailTypeList={conferenceDetailTypeList}
              onAddList={onAddList}
              key={`item-${item.orderNo}`}
            />
          );
        })}

이렇게 코드를 수정했더니 갑자기 원하던 결과를 잘 내는 것이었다..

문제는 key 였던것 같다.

key를 unique한 값으로 사용했어야 하는데 idx로 사용하다 보니 인지를 못했던것 같다.

공식문서에 key를 unique한 값으로 사용해라라고 해서 대부분 서버에서 주는 seq값을 사용하거나 없으면 item-idx형식으로 array index값을 unique하게 사용했었는데

item-idx 이런 형식이 unique한 값인줄 알았는데 아니었다.. array index를 쓰지않고 key를 unique 한 값으로 줘야 하는 것에 대해서 다시한번 알게 되는 순간이었다..

해결 결과

원하던 하단에 잘 생성이 된다..

key 값을 unique한 값으로 주도록 해보자.
나는 거의 디버깅을 하고 문제 해결 하면서 반나절의 시간을 사용했지만 누군가는 이글이 도움이 되어 빠르게 해결하길 바란다.

profile
프론트엔드 개발자 초보에서 고수까지!

0개의 댓글