웹 개발

Frontend 세미나 5주차] React Hooks - 1

Gom3rye 2022. 8. 21. 11:59

Hooks란?

먼저 side effect 개념 알기

side Effect : react 컴포넌트가 화면에 렌더링된 이후에 비동기로 처리되어야 하는 부수적인 효과

>> 데이타를 가져오려고 외부 api를 호출할 때 화면에 렌더링할 수 있는 건 뿌려주고 실제 가져 올 데이타는 비동기로 가져오는 것이 권장되고 있다. 사용자 경험 측면에 유리하도록

-> 즉, 요구되어지는 effect 이외에 다른 effect가 발생하는 현상으로 Hook은 이 side effect를 수행하는 역할은 한다.

- 함수현 컴포넌트에서 사용되어지는 몇 가지 기술을 hook이라고 한다.
- 함수형 컴포넌트에서 상태 관리를 할 수 있는 useState, 렌더링 지표에 작업을 설정하는 useEffect 등의 다양한 기능을 제공한다.

- side effect를 줄여 그냥 effect라고도 한다.

 

클래스형 컴포넌트의 단점

- 클래스 문법 어려움

- 축소 어려움

- reloading의 신뢰성이 떨어짐

- 최신 기술의 적용이 효과적이지 않음

But, 함수형 컴포넌트로는 life cycle 관리나 state 같은 기능을 사용할 수 없음

=> Hook을 사용해 함수형 컴포넌트도 클래스형 컴포넌트의 기능을 사용할 수 있도록 하자!

useState

: 소괄호 안에 있는 코드의 실행 결과를 콘솔에 출력하는 함수

 

const [state, setState] = useState (초기값)   // 인자로 초기값을 받는다.

  • state : 변수. But, 일반 변수와는 다르게 값이 변하면 렌더링이 일어난다. 즉, 값이 변하게 되면 연관있는 컴포넌트들이 다시 렌더링이 되어 화면이 바뀐다.
  • setState : state 값을 변경시켜주는 함수
  • useState : state, setState를 return 하면서 초기값을 설정해주는 hook

주의 : state 값을 3으로 바꾸고 싶어서 state = 3을 하면 X, 왜냐하면 렌더링이 일어나지 않기 때문!

setState(3)을 해야지 렌더링이 일어나고 state 값이 변경된다.

 

사용 방법

function Example() {
const [count, setCount] = useState(0);

return (
  <div>
   <p> You clicked {count} times </p>
   <button onClick={() => setCount(count + 1)}> Click me </button>
  </div>
 );
}

useEffect

: React 에서 제공 내장 라이브러리 api 함수로 Side Effect를 함수형에서 사용할 수 있게 하는 리액트 hooks

- 리액트 컴포넌트가 렌더링 될 때마다 특정 작업을 실행할 수 있도록 하는 Hook

- component가 mount 됐을 때, unmount 됐을 때, update 됐을 때 특정 작업 처리 가능

 

useEffect(function, deps)

  • function : 수행하고자 하는 작업 (ex, 실행시키고자 하는 함수)
  • deps : 배열 형태이며, 배열 안에는 검사하고자 하는 특정 값, or 빈 배열

사용법

1. 컴포넌트가 mount 되었을 때 (처음 렌더링 됐을 때, 나타났을 때)
- deps가 없음 : 해당 컴포넌트가 렌더링 됄 때마다 useEffect가 실행된다.

useEffect(() => { console.log("렌더링 될 때마다 실행"); });

- deps에 빈 배열 있음 : 처음 렌더링 될 때 한 번만 실행된다.

useEffect(() => { console.log("맨 처음 렌더링 될 때 한 번만 실행"); }, []);

2. 컴포넌트가 update 될 때 (특정 props나 state값이 바뀔 때)

- 특정 값이 업데이트 될 때 실행하고 싶으면 deps 위치의 배열 안에 검사하고 싶은 값을 넣어준다.

useEffect(() => {
   console.log(count);
   console.log("업데이트 될 때마다 실행");
}, [count]);

3. 컴포넌트가 unmount 될 때(사라질 때), update 되기 직전에

- unmount 될 때만 cleanup함수를 실행하고 싶을 때 => 두번째 파라미터로 빈 배열 넣기

- 특정 값이 없데이트 되기 직전에 cleanup함수를 실행하고 싶을 때 => deps 배열 안에 검사하고 싶은 값 넣기

useEffect(() => {
   console.log("컴포넌트 나타남");
   console.log(name);
   return () => {
      console.log("cleanup 함수");
   };
});   // deps 비어있음 -> 컴포넌트가 사라질 때 cleanup 함수 호출됨

* cleanup함수 : useEffect에 대한 뒤정리를 해주는 함수로 effect가 호출되기 전과 컴포넌트가 unmount 되면서 이전 effect를 정리하는 역할을 한다.

- cleanup함수가 먼저 출력되고 effect가 호출되는 것을 확인할 수 있다. (cleanup 함수 > 컴포넌트 나타남 > 닉네임 결혼)

Ex)

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

function UseEffect() {
   const [name, setName] = useState("초기 닉네임");
   
   useEffect(() => {
      console.log("컴포넌트 나타남");   //2
      console.log(name);
      return () => {
         console.log("cleanUp 함수");   //1
      };
   });

   const onClick = () => {
      setName("닉네임 변경");   //3 (새로운 effect 호출됨)
   };
   return (
      <div>
         {theme} <button onClick = {onClick}> 변경 </button>
      </div>
   };
}

Todo List 실습

- todo 관련 변수 선언

const [todos, setTodos] = useState([]);
const [todo, setTodo] = useState("");

- input에 onChange 함수를 통해서 이벤트를 인식하고 화살표 함수로 이벤트를 받아서 전달을 해줘야 한다.

<input type ="text" 
 onChange = {(e) => { setTodo(e.target.value); }}
 value = {todo}
 />

- onSubmit을 통해서 값을 전송할 때 handle submit 함수를 실행하도록 해보자 (새롭게  저장된 값을 todos에 추가해주기 위해)

- 먼저 선언을 해야 한다.

const handleSubmit = (e) => {
 e.preventDefault();   // 브라우저의 기본 액션을 방지하는 handle submit 함수, ex) add todo를 누를 때 원하지 않는 새로 고침이 생길 수 있다.
 const newTodo = {
   id : new Date().getTime(),
   text : todo,
   complete : false,
   };
 setTodos(newTodos);   // But, 기존 값이 있는 경우에는 우리가 추가한 값이 들어온 채로 초기화 되어 버리니까 기존의 todos 값들이 있다면 앞의 객체에 뒤이어서 새로운 객체를 붙이는 방식으로 구현해야 한다.
                       // 여러가지 방식이 있지만 여기선 spread 연산자를 통해 기존 객체를 복제한 후 새로운 todo를 추가하겠다.
};
<form onSubmit={handleSubmit}>
 <input type ="text" 
  onChange = {(e) => { setTodo(e.target.value); }}
  value = {todo}
  />
 <button type="submit"> Add Todo </button>
</form>
const handleSubmit = (e) => {
 e.preventDefault();   // 브라우저의 기본 액션을 방지하는 handle submit 함수, ex) add todo를 누를 때 원하지 않는 새로 고침이 생길 수 있다.
 const newTodo = {
   id : new Date().getTime(),
   text : todo,
   complete : false,
   };
 setTodos([...todos].concat(newTodo));
 console.log(newTodo);
};

- 하지만 위의 방식으로 하면 text 칸에 기존 값들이 지워지지 않고 계속 남아 있음 -> setTodos(); 다음 setTodo(""); 를 토해 비우자.

- todo list들을 받아와서 map에 뿌려주는 flow

{todos.map((todo) => (
  <div key={todo.id} className="todo">
    <div className="todo actions"> {todo.text} </div>
  </div>
))}

- useState를 통해 추가하는 것은 완료! 이제 삭제 기능을 만들어보자.

function deleteTodo(id) {
  const updateTodos = [...todos].filter((todo) => todo.id !== id);
  setTodos(updateTodos);
 }
{todos.map((todo) => (
  <div key={todo.id} className="todo">
    <div className="todo actions"> {todo.text} </div>
    <button onClick={() => deleteTodo(todo.id)}> delete </button>
  </div>
))}

- back과 연동해서 만드는 todo가 아니기 때문에 기존의 todo도 불러와서 랜더링 될 수 있게끔 useEffect를 사용해서 만들어보자.

- import loadTodo from "./data.json"; 으로 json 파일 불러오기 (여기에 data들이 담길 예정)

- 새로고침을 누를 때 한번만 실행되면 되므로 useEffect에 빈 배열을 넣어주면 된다.

useEffect(() => {
  setTodos(loadTodo);
}, []);

- 아래는 data.json 파일 내용

[
  {
    "id" : 1,
    "text" : "useState 배우기",
    "completed" : false
  },
  {
    "id" : 2,
    "text" : "useEffect 배우기",
    "completed" : false
  }
]

 

728x90
반응형