TIL/React

[React hook]useEffect

매망쩔 2023. 1. 8. 18:40

https://www.youtube.com/watch?v=kyodvzc5GHU 처음 공부하시는 거라면 이 영상 추천드립니다.

 

 

1. useEffect란?

mount , update, unmount 될 때, 특정 작업을 실행해주고 싶을 때 사용하는 훅

 

이때 useEffect는 주로 함수내에 넣는데 이 이유는 공식 문서에서 다음과 같이 나온다.

--------

useEffect구성 요소 내부에서 호출되는 이유는 무엇 입니까? useEffect구성 요소 내부에 배치 count하면 효과에서 바로 상태 변수(또는 모든 소품)에 액세스할 수 있습니다. 이를 읽기 위해 특별한 API가 필요하지 않습니다.

---------

2. useEffect의 형태

useEffect = (()=> {
//기본형태 콜백함수를 가짐
} )

//,.....

useEffect = (()=>{
// value일 때만 작동
},[value])

기본적으로 콜백함수를 가진 형태를 띔

첫 번째 경우는 랜더링시 마다 useEffect 내부의 함수를 실행합니다.

하지만 매 랜더링마다 특정함수를 사용하게 되면,  리소스를 너무 많이 소비하게 됩니다.

 

이때 아래의 경우처럼 2번째 인자로 최적화가 가능합니다.

 

두 번째 useEffect 의 경우에 [value]를 두 번째 인자로 받고 있습니다.

 

이 배열은 디펜던시 어레이라고 부르며, 아래의 useEffect는 마운트 될 때, 두 번 배열속의 value 값이 바뀔 때 실행합니다.

 

예시 ) 항해 심화주차 counter를 통해서

// src/App.jsx

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

const App = () => {
  const [todo, setTodo] = useState({
    title: "",
  });
  const [todos, setTodos] = useState(null);

  // patch에서 사용할 id, 수정값의 state를 추가
  const [targetId, setTargetId] = useState(null);
  const [editTodo, setEditTodo] = useState({
    title: "",
  });

  const fetchTodos = async () => {
    const { data } = await axios.get("http://localhost:3001/todos");
    setTodos(data);
  };

  const onSubmitHandler = async (todo) => {
    const { data } = await axios.post("http://localhost:3001/todos", todo);
    setTodos([...todos, data]);
  };

  const onClickDeleteButtonHandler = async (todoId) => {
    await axios.delete(`http://localhost:3001/todos/${todoId}`);
    setTodos([...todos]);
    // fetchTodos();
  };

  // 수정버튼 이벤트 핸들러 추가 👇
  const onClickEditButtonHandler = (todoId, edit) => {
    axios.patch(`http://localhost:3001/todos/${todoId}`, edit);
    fetchTodos();
  };

  // // 무한 랜더링이 됨 why? fetchTodos안에 setTodos가 todos의 state를 바꾸기 때문에, 랜더링 일어나고, 랜더링시 다시 useEffect
  // useEffect(() => {
  //   fetchTodos();
  // });
  /////마운트 시에만 사용
  // useEffect(() => {
  //   fetchTodos();
  // }, []);

  useEffect(() => {
    fetchTodos();
  }, [todos]);

  return (
    <>
      <form
        onSubmit={(e) => {
          e.preventDefault();
          onSubmitHandler(todo);
        }}
      >
        {/* 👇 수정기능에 필요한 id, 수정값 input2개와 수정하기 버튼을 추가 */}
        <div>
          <input
            type="text"
            placeholder="수정하고싶은 Todo ID"
            onChange={(ev) => {
              setTargetId(ev.target.value);
            }}
          />
          <input
            type="text"
            placeholder="수정값 입력"
            onChange={(ev) => {
              setEditTodo({
                ...editTodo,
                title: ev.target.value,
              });
            }}
          />
          <button
            // type='button' 을 추가해야 form의 영향에서 벗어남
            type="button"
            onClick={() => onClickEditButtonHandler(targetId, editTodo)}
          >
            수정하기
          </button>
        </div>
        <input
          type="text"
          onChange={(ev) => {
            const { value } = ev.target;
            setTodo({
              ...todo,
              title: value,
            });
          }}
        />
        <button>추가하기</button>
        <button>추가하기</button>
        <button>추가하기</button>
      </form>
      <div>
        {todos?.map((todo) => (
          <div key={todo.id}>
            {/* todo의 아이디를 화면에 표시 */}
            {todo.id} :{todo.title}
            <button
              type="button"
              onClick={() => onClickDeleteButtonHandler(todo.id)}
            >
              삭제하기
            </button>
          </div>
        ))}
      </div>
    </>
  );
};

export default App;

 

하지만 위의 2경우에 경우를 통해서 함수를 실행했을 때, 그 함수를 종료하는 기능이 없다.

이때 구독했던 함수를 종료하는 것을 Clean up이라고 한다.

useEffect = (() => {
//구독하기

return ()=> {
 //구독해지
}
},[])

 

 

 

 

 

참고자료 : https://reactjs.org/docs/hooks-effect.html

 

Using the Effect Hook – React

A JavaScript library for building user interfaces

reactjs.org