[React] Axios로 Express 서버와 연동하기 (3) useState 무한실행 탈출방법

쥬롬의 코드착즙기·2022년 11월 2일
0

TIL : Today I learned

목록 보기
6/10
post-thumbnail

본문은 라매개발자 강의 프론트에서 서버에 데이터 요청하는 방법 (React로 fetch, axios 사용하기)를 기반으로 작성되었습니다.

📌 화면에 띄워보자

지난 글에서 클라이언트가 받아온 서버 데이터를 console.log로 확인했다.
이번에는 서버 데이터를 화면에 띄워 보자.

✅ useState

useState는 state 값 변화가 생기면 리렌더링해서 화면에 새로운 값을 보여준다.
useState를 써서 서버 데이터에 따라 화면이 달라지도록 만들어보자.
console.log로 보여줬던 데이터를 setState의 파라미터로 넘겨준다.

function App() {
  const [todoList, setTodoList] = useState(null);

  fetch('http://localhost:4000/api/todo')
  .then((res)=>res.json())
  .then((data)=>setTodoList(data));
//이하 생략

그런데 이렇게 하면 무한리렌더링 지옥에 갇힌다.
(영상에서는 갇힌다... 나도 전에 갇혔었다... 근데 왜 지금은 안 갇히지??)

❌ useEffect 무한 리렌더링

무한 리렌더링이 되는 이유를 알기 위해서는 useState의 작동원리에 대해 알아야 한다.

문제의 코드는 여기다.

function App() {
  const [todoList, setTodoList] = useState(null);
  fetch('http://localhost:4000/api/todo')
  .then((res)=>res.json())
  .then((data)=>setTodoList(data));
  return(
    //생략

리액트는 컴포넌트를 최초로 렌더링했을 때 코드를 한 줄씩 실행한다.
첫 실행때 useState를 만나 state를 만든다.
그리고 fetch 함수로 들어가는데, 서버로부터 응답을 받기까지 시간이 조금 걸린다.
함수 실행이 끝나기 전에 return문으로 와서 화면을 보여준다.
fetch가 끝났다. setTodoList를 해 준다.
어? 근데 state가 바뀌었다. 리렌더링을 해줘야 한다.
그러면 코드가 처음부터 다시 실행된다.

✨ 정리
첫 렌더링 ➡ useState(null)
➡ fetch(), 서버 응답 대기 중 return()
➡ 서버 응답 완료 후 setTodoList(data)
➡ state 변화로 인한 리렌더링, 처음부터 다시 실행
➡ fetch(), 서버 응답 대기 중 return()
...

무한반복

고치기 위해서는 딱 한 번만 실행되도록 하면 되는데 이게 useEffect이다.

✅ useEffect

useEffect는 컴포넌트가 처음 나타날 때 (mount), 컴포넌트가 사라질 때 (unmount), 컴포넌트가 업데이트 될 때 (re-render)를 관리한다.
(useEffect에 관해 전에 정리했던 게시물도 있다... 참고!)
지금 필요한 것은 컴포넌트가 처음 나타날 때(mount시)에만 fetch시키는 것.
코드를 이렇게 수정해 준다.

function App() {
  const [todoList, setTodoList] = useState(null);
  useEffect(() => {
    fetch('http://localhost:4000/api/todo')
    .then((res)=>res.json())
    .then((data)=>setTodoList(data));
  }, [])

  return (
    //이하생략

❌ Cannot read properties

또다른 에러가 있다...

state 초기값이 null이라서 이러는거 같다.

✅ useState 초기값 맞는 자료형으로

구글신께 여쭤보니 null 대신 초기값의 자료형을 알려주면 된다고 한다.
useState를 null로 초기화했던 부분을 바꿔주자.
데이터는 배열로 넘어오니까 빈 배열로 초기화한다.

  const [todoList, setTodoList] = useState([]);

그럼 다시 잘 돌아간다.

✅ null 일때는 map 실행하지 않기

그런데 영상 조금 더 보면... 해결법을 알려주신다.
todoList가 null일때는 실행하지 않도록 하는 것이다.
map 메소드 앞에 물음표를 넣어 준다.

      {todoList?.map((todo)=>(

이러면 또 잘 돌아간다.

💻 map으로 화면에 띄우기

data는 배열 형식이니 map 메소드로 하나씩 화면에 띄워준다.
map은 배열 안 각각의 element에 대해 실행된다.

return 문 안을 아래와 같이 수정해준다.

  return (
    <div className="App">
      <h1>TODO LIST</h1>
      {todoList.map((todo)=>(
        <div>
          <div>{todo.id}</div>
          <div>{todo.text}</div>
          <div>{todo.done ? 'Y' : 'N'}</div>

        </div>
      ))}
    </div>
  );

화면에 서버에서 넘긴 데이터가 잘 뜬다면 성공!

📌 전체 코드

client/App.js

import React from "react";
import {useState,useEffect} from "react";

function App() {
  const [todoList, setTodoList] = useState(null);

  useEffect(() => {
    fetch('http://localhost:4000/api/todo')
    .then((res)=>res.json())
    .then((data)=>setTodoList(data));
  }, [])

  return (
    <div className="App">
      <h1>TODO LIST</h1>
      {todoList?.map((todo)=>(
        <div>
          <div>{todo.id}</div>
          <div>{todo.text}</div>
          <div>{todo.done ? 'Y' : 'N'}</div>

        </div>
      ))}
    </div>
  );
}

export default App;
profile
코드를 짭니다...

0개의 댓글