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

똘이77님의 프로필 이미지
똘이77

작성한 질문수

파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트

리액트 axios 데이터 받아와서 랜더링 질문드립니다

해결된 질문

작성

·

2.5K

0

useState로 postList라는 이름의 state를 선언한 후 axios를 통해 얻은 결과를 setPostList를 통해 postList에 업데이트 시키고 . 그러면 state가 변경되었으므로 새롭게 렌더링이 되고 -> return이 다시 불리며 -> 변경된 값을 화면에 업데이트 시켜줄 주는걸로 알고있는데

 

function PostList() {


  const [postList, setPostList] = useState([]);
  //const headers = { Authorization: `JWT ${jwtToken}` };

    const [{ data: originPostList, loading, error }, refetch] = useAxios({
    url: "/api/posts/",
    //headers
  });

  useEffect(() => {
    setPostList(originPostList);

    console.log("mouted");
  }, [originPostList]);


  console.log("loaded respaonse2 :", postList);

  return (
  <div>

      {postList && postList['results'].length === 0 && (
        <Alert type="warning" message="포스팅이 없습니다. :-(" />
      )}
      {postList &&
        postList['results'].map(post => (
          <Post post={post} key={post.id}  />
        ))}
    </div>
  );
}

export default PostList;

loaded respaonse2 : []

loaded respaonse2 : []

loaded respaonse2 : []

loaded respaonse2 : []

콘솔창에 이렇게 4번이 뜹니다

어쩔때는 postList에 데이터가 들어가서 나오는데

useEffect에서 셋 시켜서 데이터가 들어갔는데도 빈 데이터가 나오는지 궁굼합니다.

return 문에 postList 가져오는 구문을 없애면 제대로 들어가는데 예외처리를 했는데도 map 찾을수 없다는 에러가 뜹니다

그리고 Simple jwt 토큰 인증을 쓰지 않으면 데이터는 잘가져옵니다

 

답변 1

0

이진석님의 프로필 이미지
이진석
지식공유자

안녕하세요.

함수 컴포넌트 바로 아래 depth의 코드들은 해당 컴포넌트가 렌더링될 때마다 수행이 됩니다. 그러니 아직 setPostList에 의해서 데이터가 채워지기 전인데 PostList 컴포넌트의 상탯값이 바뀌는 등의 여러가지 이유로 재렌더링이 발생한다면 쓰신 loaded respaonse2 메세지는 여러 번 출력될 수 있습니다.

그리고 originPostList를 바라보는 useEffect에서는

- useAxios를 통해 받은 originPostList 상탯값의 초기값은 undefined이며, API 응답을 받게 되면 이 후에 상탯값이 변경되게 되겠죠.

- 그러니 originPostList를 바라보는 useEffect에 지정된 함수는 첫번째 호출에서 originPostList가 undefined일 때 호출이 됩니다. 그러니 useEffect 내에서 originPostList 값이 undefined가 아닐때 setPostList를 호출할 수 있도록 방어적으로 코드를 작성해주시는 것이 좋습니다.

Uncaught TypeError: Cannot read properties of undefined (reading 'map') 에러가 발생하신다면, 해당 객체에서 지원하지 않는 속성명을 참조하여 undefined를 읽어왔고 그 undefined에 대해서 .map 을 수행했기에 발생하는 오류입니다.

그 당시의 postList 정확한 값을 확인해보셔야 합니다. 예상하신 것과는 다른 형태의 객체이실 수도 있습니다. postList라고 한다면 Array 형태를 예상하셨을 수 있는 데, Array에 "results"로 참조하는 것은 있을 수 없는 속성 참조일 수 있습니다. postList가 Array가 아닌 object일까요?

정확한 확인을 위해 PostList 컴포넌트에서 return 에서 results 코드를 모두 제거하고, 아래의 코드로 postList 객체의 값을 화면에 그대로 찍어보면 어떤 값이 나오나요?

{JSON.stringify(postList)}

확인해보시고, 댓글 부탁드립니다.

화이팅입니다. :-)

똘이77님의 프로필 이미지
똘이77
질문자

unction PostList() {
    
    const [postList, setPostList] = useState([]);
    //const headers = { Authorization: `JWT ${jwtToken}` };

    const [{data: originPostList, loading, error}, refetch] = useAxios({
        url: "/api/posts/",
        //headers
    });

    useEffect(() => {

        if (originPostList) {
            console.log("originPostList", originPostList);
            setPostList(originPostList);

        }

        console.log("mouted");


    }, [originPostList]);

    console.log("loaded respaonse2 :", postList);

    return (
        <div>

            {postList['results'] && postList['results'].length === 0 && (
                <Alert type="warning" message="포스팅이 없습니다. :-("/>
            )}
            {postList['results'] &&
                postList['results'].map(post => (
                    <Post post={post} key={post.id}/>
                ))}

        </div>
    );
}

export default PostList;

말씀하신대로 undefined 가 아닐경우만 들어가게 해서 데이터는 잘 바인딩 됩니다

그런데

loaded respaonse2 : []

PostList.js:26 mouted

PostList.js:31 loaded respaonse2 : []

PostList.js:31 loaded respaonse2 : []

PostList.js:21 originPostList {count: 2, next: null, previous: null, results: Array(2)}

PostList.js:26 mouted

PostList.js:31 loaded respaonse2 : {count: 2, next: null, previous: null, results: Array(2)}

이렇게 재랜더링이 4번이 되는데 리액트 생명주기를 제대로 짯는지 여쭤봅니다

이진석님의 프로필 이미지
이진석
지식공유자

위 코드 상으로는 큰 이슈가 없어보입니다. 재렌더링은 해당 컴포넌트 뿐만 아니라 부모 컴포넌트의 재렌더링 시에도 재렌더링이 발생할 수도 있습니다. 재렌더링 최적화를 처음부터 과하게 신경쓰실 필요는 없구요. 과한 최적화는 오히려 독이 됩니다.

setPostList를 통해 object, 즉 {} 값을 설정하시는 데
postList 상탯값의 초기값은 array,즉 [] 로 두셨네요. 초기값을 {} 로 두시거나
setPostList 시에 array인 results 값만 상탯값에 반영하시는 것이 보다 나은 접근일 것입니다.

화이팅입니다. :-)

똘이77님의 프로필 이미지
똘이77
질문자

감사합니다!

똘이77님의 프로필 이미지
똘이77

작성한 질문수

질문하기