본문 바로가기
프레임워크&라이브러리/React.js

[Trouble Shooting] setTags가 왜 not a function이지?

by whale in milktea 2023. 7. 22.
문제상황 : 자식 컴포넌트에서 부모 컴포넌트로 string[] 타입의 데이터를 상태 끌어올리기를 활용하여 구현하고 있는 도중에 not a function error가 콘솔에 표시되면서 페이지 전체의 렌더링이 되지 않음

추론1. 내가 아직 자바스크립트의 인터프리팅 체계에 대한 이해가 부족해서 당연한 메서드를 잘못된 위치에서 호출하고 있는 것은 아닐까?
=> 문제가 위치한 레이어 : 단위 함수

추론2. 타입의 설정이 잘못되어 있는 것은 아닐까?
=> 문제가 위치한 레이어 : 인터페이스 타입 설정

추론3. 부모 컴포넌트와 자식 컴포넌트의 Props 전달과정 혹은 타입 정의 과정에서 각자 다른 타입/함수를 사용한 경우 타입 추론에 의해 자식 컴포넌트에서 함수로 인식하지 않을 수도 있지 않을까?
=> 문제가 위치한 레이어 : 부모 컴포넌트의 상태변경함수 사용 함수

결론, 추론 2번이 정답!

 

import { useState } from "react";
import { TagsInput } from "react-tag-input-component";
import styled from "styled-components";

interface PropsType {
  setTags: (tags: string[]) => void;
}

const NewTagInput = ({ setTags }: PropsType) => {
  const [selected, setSelected] = useState<string[]>([]);

  setTags(selected);

  return (
    <TagInputWrapper>
      <TagsInput
        value={selected}
        onChange={setSelected}
        name="tags"
        placeHolder="기술 스택을 입력해주세요"
      />
    </TagInputWrapper>
  );
};

const TagInputWrapper = styled.div`
  display: block;
`;

export default NewTagInput;

 

추론1 : 자식 컴포넌트의 이벤트 핸들링 함수 구조 변경

import { useState } from "react";
import { TagsInput } from "react-tag-input-component";
import styled from "styled-components";

interface PropsType {
  setTags: (tags: string[]) => void;
}

const NewTagInput = ({ setTags }: PropsType) => {
  const [selected, setSelected] = useState<string[]>([]);
  
  // 타입은 나중에 다시 설정해줘도 되니, 일단 any로 두고 동작여부 및 데이터 전달만 체크!
  const handleOnChange = (e: any) => {
    console.log(e)
    setSelected(e);
    setTags(selected);
  };

  return (
    <TagInputWrapper>
      <TagsInput
        value={selected}
        onChange={handleOnChange}
        name="tags"
        placeHolder="기술 스택을 입력해주세요"
      />
    </TagInputWrapper>
  );
};

const TagInputWrapper = styled.div`
  display: block;
`;

export default NewTagInput;

이렇게 변경하니 결국 동일하게 "Uncaught TypeError: setTags is not a function" 에러가 뜬다.

그럼 결국 타입 에러일 가능성이 높다! (쥔장..)

 

2. 타입의 설정이 잘못되어 있는 것은 아닐까?

interface PropsType {
  setTags: (tags: string[]) => void;
}

참고자료 : https://whoyoung90.tistory.com/45

 

setState is not a function

부모 컴포넌트의 boolean 상태값을(모달창 온오프) 자식 컴포넌트로 넘겨서 사용하던 도중 해당 오류를 접하게 되었다. Uncaught TypeError: setState is not a function 해당 오류의 해결책으로는 2가지 해결책

whoyoung90.tistory.com

* 현재 설정한 코드는 다음과 같이 동작한다.

1. tag라는 변수로 정의된 (실제 코드에서는 다른 변수명을 사용해도 상관없다.) 어떤 값을 인자로 전달받는다

2. tag는 string 타입으로 구성된 요소들이 들어있는 배열이다.

3. 이 함수는 인자을 전달받아서 내부 로직을 돌릴 뿐, 별도의 return 값을 지정하지 않는다.

why? useState는 상태변수에 할당하는 내부 로직이 setState 함수 내부에 들어있기 때문이다.

 

이 생각대로 + 구글링에 나와있는대로 작성했더니 "not a function" 에러가 떴다.

그렇다면 setState를 인자로 전달할 때는, 어떻게 전달할지 또 구글링 + 코드에 밑줄을 일일이 hover해 봤다.

헤헷,, 이미, 내가 할 행동에 대한 타입을 너는 추론하고 있었구나..

interface PropsType {
  setTags: React.Dispatch<React.SetStateAction<string[]>>;
}

추가적인 구글링과 학습을 통해 이렇게 코드를 수정했더니! 잘 동작한당!

 

React.Dispatch<React.SetStateAction<string[]>>

1. React.Dispatch<> : React 클래스 내부에서 어떤 값을 업데이트 하고자 할 때, 사용할 수 있는 제네릭 타입

(내부에 여러 타입들이 변수처럼 재할당 가능한 형태로 정의되어 있음)

2. React.SetStateAction<> : 값를 업데이트 할 때, React에서 자체적으로 정의한 여러 메서드들 중에 setState를 업데이트 할 때 사용하는 제네릭

3. <String[]> : String 요소로 구성된 배열들이 setState에 들어갈 수 있다. === state는 string 요소로 구성된 배열이다.

 

* (tags : <string[]>) => void 와의 차이

- 그냥 인자로 문자열 요소들로 구성된 배열을 받는다 빼고는 다 다름!

- 특히 내가 오해했던 부분은 setState의 내부로직을 완전히 까본게 아니기 때문에 인터프리팅 과정에서 어떤 지점에서 버그가 등장할 지 알 수 없음!

- 따라서, 반드시! 이미 정의된 타입이 있는지 점검할 필요가 있음! Why? 시간을 줄일 수 있음! + 타입스크립트의 추론을 200% 활용하장!

'프레임워크&라이브러리 > React.js' 카테고리의 다른 글

React-Quill을 활용한 구현 예제  (0) 2023.04.16
React-quill을 활용한 구현 예제  (0) 2023.04.13
(Rich-TextEditor) React-quill  (0) 2023.04.12
(SPA) React-Router-Dom  (0) 2023.03.06
UseRef()  (0) 2023.02.22