Notice
Recent Posts
Recent Comments
«   2026/01   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

MJ.Story

React Hooks(useState, useEffect) 본문

IT/React

React Hooks(useState, useEffect)

아토씌 2022. 12. 8. 23:14

React Hooks(useState, useEffect)

styled-components

  • 리액트에서 css-in-JS방식으로 component를 꾸밀 수 있게 도와주는 패키지

사용법

  • 설치 - yarn add styled-components
  • Extensions - vscode-styled-component 설치
// styled키워드를 사용해서 styled-components 방식대로 컴포넌트를 만듭니다.
import styled from "styled-components";
// 그리고 이안에 스타일 코드를 작성합니다. 스타일 코드는 우리가 알고 있는 css와 동일
// div말고 원하는 태그 넣어서 사용 가능
const StBox = styled.div` 
	width: 100px;
	height: 100px;
	border: 1px solid ${(props) => props.borderColor};
	margin: 20px;
`;

// 1. styled-components를 만들었습니다.
const App = () => {
  return (
    <div>
      {/* 2. 위에서 만든 styled-components를 사용했습니다. */}
      {/* 3. props를 통해 borderColor라는 값을 전달했습니다. */}
      <StBox borderColor="red">빨간 박스</StBox>
      <StBox borderColor="green">초록 박스</StBox>
      <StBox borderColor="blue">파랑 박스</StBox>
    </div>
  );
};
import React from "react";
import styled from "styled-components";

const StBox = styled.div`
  width: 100px;
  height: 100px;
  border: 1px solid ${(props) => props.borderColor};
  margin: 20px;
`;

const boxList = ["red", "green", "blue"];

const getBoxName = (color) => {
  switch (color) {
    case "red":
      return "빨간 박스";
    case "green":
      return "초록 박스";
    case "blue":
      return "파란 박스";
    default:
      return "검정 박스";
  }
};

const App = () => {
  return (
    <div>
      {boxList.map((box) => (
        <StBox borderColor={box}>{getBoxName(box)}</StBox>
      ))}
    </div>
  );
};

export default App;

함수형 업데이트

  • 함수형 업데이트란?
    • setState를 사용하는 방식에는 우리가 알고 있는 방식이 아닌 또 다른 방식이 있습니다. 함수형 업데이트 방식입니다.
  1. 기존 방식
import { useState } from "react";

const App = () => {
  const [number, setNumber] = useState(0);
  return (
    <div>
			{/* 버튼을 누르면 1씩 플러스된다. */}
      <div>{number}</div> 
      <button
        onClick={() => { // 1씩 올라감
          setNumber(number + 1); // 첫번째 줄 
          setNumber(number + 1); // 두번쨰 줄
          setNumber(number + 1); // 세번째 줄
        }}
      >
        버튼
      </button>
    </div>
  );
}

export default App;

2.함수형 업데이트

import { useState } from "react";

const App = () => {
  const [number, setNumber] = useState(0);
  return (
    <div>
      <div>{number}</div>
      <button
        onClick={() => { // 3씩 올라감
          setNumber((previouseState) => previouseState + 1);
          setNumber((previouseState) => previouseState + 1);
          setNumber((previouseState) => previouseState + 1);
        }}
      >
        버튼
      </button>
    </div>
  );
};

export default App;

왜 다르게 동작할까?

  • 일반 업데이트 방식은 버튼을 클릭했을 때 첫번째 줄 ~ 세번째 줄의 있는 setNumber가 각각 실행되는 것이 아니라 배치(batch)로 처리합니다. 즉 우리가 onClick을 했을 때 setNumber 라는 명령을 세번 내리지만,리액트는 그 명령을 하나로 모아 최종적으로 한번만 실행을 시킵니다. 그래서 setNumber을 3번 명령하던, 100번 명령하던 1번만 실행됩니다.
  • 반면 함수형 업데이트 방식은 3번을 동시에 명령을 내리면, 그 명령을 모아 순차적으로 각각 1번씩 실행 시킵니다. 0에 1더하고, 그 다음 1에 1을 더하고, 2에 1을 더해서 3이라는 결과가 우리 눈에 보이는 것이죠
  1. 정리
  • useState의 업데이트 방식은 2가지 방식이 있으며, 각각 다르게 동작
  • useState로 원시데이터가 아닌 데이터를 변경할떄는 불변성을 유지

useEffect

  • useEffect는 언제 사용할까?
    • useEffect는 리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook입니다. 쉽게 말해 어떤 컴포넌트가 화면에 보여졌을 때 무언가를 실행하고 싶다면, 또는 어떤 컴포넌트가 화면에서 사라졌을 때 무언가를 실행하고 싶다면? useEffect를 사용합니다.
    • useState와 마찬가지로 React에서 제공하는 훅(기능) 이므로, import React, {useEffect}from”react”; 로 import해서 사용합니다.
  • 코드로 보는 useEffect기초
    • 브라우저에서 우리가 App컴포넌트를 눈으로 보는 순간, 즉 App컴포넌트가 화면에 렌더링될 때 useEffect 안에 있는 console.log가 실행됩니다. 컴포넌트가 렌더링 될 때 실행된다. 이게 바로 useEffect 핵심 기능입니다.
import React, { useEffect } from "react";

const App = () => {

  useEffect(() => {
		// 이 부분이 실행된다.
    console.log("hello useEffect");
  });

  return <div>Home</div>;
}

export default App;
  • useEffect와 리렌더링(re-rendering)
    • useEffect는 useEffect가 속한 컴포넌트가 화면에 렌더링 될 때 실행됩니다. 이런 useEffect의 특징에 의해 우리가 의도치않은 동작을 경험할수도 있다
    • 다음 코드를 보면 input이 있고 value라는 state를 생성하여 input과 연결시켰습니다. 이렇게 구현하고 브라우저에 input에 어떤 값을 입력하면 useEffect가 계속 실행되는 것을 볼 수 있습니다.
import React, { useEffect, useState } from "react";

const App = () => {
  const [value, setValue] = useState("");

  useEffect(() => {
    console.log("hello useEffect");
  });

  return (
    <div>
      <input
        type="text"
        value={value}
        onChange={(event) => {
          setValue(event.target.value);
        }}
      />
    </div>
  );
}

export default App;
  • 전체 흐름
    1. input에 값을 입력
    2. value, 즉 state가 변경된다
    3. state가 변경되었기 때문에, App 컴포넌트가 리렌더링 된다.
    4. 리렌더링이 되었기 때문에 useEffect가 다시 실행된다.
    5. 1번 → 5번 과정이 계속 순환한다.
  • 정리
    • 우리는 콘솔이 브라우저에 한번만 찍히길 원했지만, input을 입력할 때마다 계속 찍히고 있는 것 입니다. 하지만 이런 부분도 해결할 수 있습니다.

의존성 배열

  1. 의존성 배열(dependency array)이란?
    • useEffect에는 의존성 배열이라는 것이 있습니다. 쉽게 얘기하면 “이 배열에 값을 넣으면 그 값이 바뀔 때만 useEffect를 실행할게” 라는 것 입니다.
    // useEffect의 두번째 인자가 의존성 배열이 들어가는 곳 입니다.
    useEffect(()=>{
    	// 실행하고 싶은 함수
    }, [의존성배열])
    
  2. 의존성 배열이 빈 배열인 경우
    • 위에 보았던 코드와 동일한 코드 다만 useEffect에 의존성 배열만 추가
    • 일단 의존성 배열안에는 어떠한 값도 넣지 않았습니다. 의존성 배열이 “이 배열에 값을 넣으면 그 값이 바뀔 때만 useEffect를 실행할게” 라는 의미를 가진다고 했고 우리가 아무것도 넣지 않았으니 useEffect는 처음에 딱 한번만 실행되고 그 이후로는 어떤일이 일어나도 실행이 되서는 안됩니다.
    // src/App.js
    
    import React, { useEffect, useState } from "react";
    
    const App = () => {
      const [value, setValue] = useState("");
      useEffect(() => {
        console.log("hello useEffect");
      }, []); // 비어있는 의존성 배열
    
      return (
        <div>
          <input
            type="text"
            value={value}
            onChange={(event) => {
              setValue(event.target.value);
            }}
          />
        </div>
      );
    }
    
    export default App;
    

의존성 배열에 빈 배열[ ]을 넣은 경우

  • input에 어떤 값을 입력하더라도, 처음에 실행된 hello useEffect외에는 더 이상 실행이 되지 않는 것을 볼 수 있습니다. 이렇게 useEffect를 사용하는데, 어떤 함수를 컴포넌트가 렌더링 될때 단 한번만 실행하고 싶으면 의존성 배열을 [ ] 빈 상태로 넣으면 됩니다.
  1. 의존성 배열에 값이 있는 경우
    • 빈 배열을 넣었을 때, 최초 렌더링 이후에는 useEffect가 실행되지 않는다는 것을 보셨죠? 그럼 이제 의존성 배열에 value 를 넣어보겠습니다. 우리가 배운게 맞다면, value는 state이고 우리가 input을 입력할 때마다 그 값이 변하게 되니 useEffect도 계속 실행이 되겠죠?
    • 콘솔이 2번 찍혀 있는 것은 useEffect로 인해 두번 실행된 것이 아니라, strict mode 라는 개발 환경이라서 그렇게 보이는 것 입니다.

clean up

클린 업이란?

  • 우리가 처음에 “어떤 컴포넌트가 화면에서 사라졌을 때 무언가를 실행하고 싶다면” 이라는 소로 시작을 했습니다. 컴포넌트가 나타났을 때 (렌더링됐을 때 === 함수 컴포넌트가 실행됐을 때) useEffect의 effect함수가 실행되는 것은 우리가 배웠으니, 이제 컴포넌트가 사라졌을 때 무언가를 어떻게 실행는 과정을 클린 업(clean up)이라고 표현합니다.

클린 업 하는 방법

  • 클린 업을 하는 방법은 간단합니다. useEffect 안에서 return을 해주고 이 부분에 실행되길 원하는 함수를 넣으면 됩니다.
import React, { useEffect } from "react";

const App = () => {

	useEffect(()=>{
		// 화면에 컴포넌트가 나타났을(mount) 때 실행하고자 하는 함수를 넣어주세요.

		return ()=>{
			// 화면에서 컴포넌트가 사라졌을(unmount) 때 실행하고자 하는 함수를 넣어주세요.
		}
	}, [])

	return <div>hello react!</div>
};

export default App;

클린 업 활용해보기

  • 속세를 벗어나는 버튼을 만들었고 버튼을 누르면 useNavigate에 의해서 /todos로 이동하면서 속세 컴포넌트를 떠날 것 입니다. 그러면서 화면에서 속세 컴포넌트가 사라질 것 이고, useEffect의 return 부분이 실행 될 것 입니다.
import React, { useEffect } from "react";
import { useNavigate } from "react-router-dom";

const 속세 = () => {
  const nav = useNavigate();

  useEffect(() => {
    return () => {
      console.log(
        "안녕히 계세요 여러분! 전 이 세상의 모든 굴레와 속박을 벗어 던지고 제 행복을 찾아 떠납니다! 여러분도 행복하세요~~!"
      );
    };
  }, []);

  return (
    <button
      onClick={() => {
        nav("/todos");
      }}
    >
      속세를 벗어나는 버튼
    </button>
  );
};

export default 속세;
  • /에서 /todos 잘 이동했고, 그 과정에서 clean up이 실행되었습니다.
  • const nav = useNavigate(); ← 이 기능은 나중에 배울 기능입니다. 다른페이지로 이동해서 컴포넌트가 사라지고, 그에 따라 클린 업이 실행되는 과정에 집중해주세요

정리

useEffect는 화면에 컴포넌트가 mount 또는 unmount 됐을 때 실행하고자 하는 함수를 제어하게 해주는 훅이다.

의존성 배열을 통해 함수의 실행 조건을 제어할 수 있다.

useEffect에서 함수를 1번만 실행시키고자 할떄는 의존성 배열을 빈 배열로 둔다

알아보면 좋은 키워드

  • Strict mode란 무엇일까?
  • React라이프 사이클이란 무엇일까?
  • React에서 말하는 mount와 unmount란 무엇일까?

React Hooks(useState, useEffect)

styled-components

  • 리액트에서 css-in-JS방식으로 component를 꾸밀 수 있게 도와주는 패키지

사용법

  • 설치 - yarn add styled-components
  • Extensions - vscode-styled-component 설치
// styled키워드를 사용해서 styled-components 방식대로 컴포넌트를 만듭니다.
import styled from "styled-components";
// 그리고 이안에 스타일 코드를 작성합니다. 스타일 코드는 우리가 알고 있는 css와 동일
// div말고 원하는 태그 넣어서 사용 가능
const StBox = styled.div` 
	width: 100px;
	height: 100px;
	border: 1px solid ${(props) => props.borderColor};
	margin: 20px;
`;

// 1. styled-components를 만들었습니다.
const App = () => {
  return (
    <div>
      {/* 2. 위에서 만든 styled-components를 사용했습니다. */}
      {/* 3. props를 통해 borderColor라는 값을 전달했습니다. */}
      <StBox borderColor="red">빨간 박스</StBox>
      <StBox borderColor="green">초록 박스</StBox>
      <StBox borderColor="blue">파랑 박스</StBox>
    </div>
  );
};
import React from "react";
import styled from "styled-components";

const StBox = styled.div`
  width: 100px;
  height: 100px;
  border: 1px solid ${(props) => props.borderColor};
  margin: 20px;
`;

const boxList = ["red", "green", "blue"];

const getBoxName = (color) => {
  switch (color) {
    case "red":
      return "빨간 박스";
    case "green":
      return "초록 박스";
    case "blue":
      return "파란 박스";
    default:
      return "검정 박스";
  }
};

const App = () => {
  return (
    <div>
      {boxList.map((box) => (
        <StBox borderColor={box}>{getBoxName(box)}</StBox>
      ))}
    </div>
  );
};

export default App;

함수형 업데이트

  • 함수형 업데이트란?
    • setState를 사용하는 방식에는 우리가 알고 있는 방식이 아닌 또 다른 방식이 있습니다. 함수형 업데이트 방식입니다.
  1. 기존 방식
import { useState } from "react";

const App = () => {
  const [number, setNumber] = useState(0);
  return (
    <div>
			{/* 버튼을 누르면 1씩 플러스된다. */}
      <div>{number}</div> 
      <button
        onClick={() => { // 1씩 올라감
          setNumber(number + 1); // 첫번째 줄 
          setNumber(number + 1); // 두번쨰 줄
          setNumber(number + 1); // 세번째 줄
        }}
      >
        버튼
      </button>
    </div>
  );
}

export default App;

2.함수형 업데이트

import { useState } from "react";

const App = () => {
  const [number, setNumber] = useState(0);
  return (
    <div>
      <div>{number}</div>
      <button
        onClick={() => { // 3씩 올라감
          setNumber((previouseState) => previouseState + 1);
          setNumber((previouseState) => previouseState + 1);
          setNumber((previouseState) => previouseState + 1);
        }}
      >
        버튼
      </button>
    </div>
  );
};

export default App;

왜 다르게 동작할까?

  • 일반 업데이트 방식은 버튼을 클릭했을 때 첫번째 줄 ~ 세번째 줄의 있는 setNumber가 각각 실행되는 것이 아니라 배치(batch)로 처리합니다. 즉 우리가 onClick을 했을 때 setNumber 라는 명령을 세번 내리지만,리액트는 그 명령을 하나로 모아 최종적으로 한번만 실행을 시킵니다. 그래서 setNumber을 3번 명령하던, 100번 명령하던 1번만 실행됩니다.
  • 반면 함수형 업데이트 방식은 3번을 동시에 명령을 내리면, 그 명령을 모아 순차적으로 각각 1번씩 실행 시킵니다. 0에 1더하고, 그 다음 1에 1을 더하고, 2에 1을 더해서 3이라는 결과가 우리 눈에 보이는 것이죠
  1. 정리
  • useState의 업데이트 방식은 2가지 방식이 있으며, 각각 다르게 동작
  • useState로 원시데이터가 아닌 데이터를 변경할떄는 불변성을 유지

useEffect

  • useEffect는 언제 사용할까?
    • useEffect는 리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook입니다. 쉽게 말해 어떤 컴포넌트가 화면에 보여졌을 때 무언가를 실행하고 싶다면, 또는 어떤 컴포넌트가 화면에서 사라졌을 때 무언가를 실행하고 싶다면? useEffect를 사용합니다.
    • useState와 마찬가지로 React에서 제공하는 훅(기능) 이므로, import React, {useEffect}from”react”; 로 import해서 사용합니다.
  • 코드로 보는 useEffect기초
    • 브라우저에서 우리가 App컴포넌트를 눈으로 보는 순간, 즉 App컴포넌트가 화면에 렌더링될 때 useEffect 안에 있는 console.log가 실행됩니다. 컴포넌트가 렌더링 될 때 실행된다. 이게 바로 useEffect 핵심 기능입니다.
import React, { useEffect } from "react";

const App = () => {

  useEffect(() => {
		// 이 부분이 실행된다.
    console.log("hello useEffect");
  });

  return <div>Home</div>;
}

export default App;
  • useEffect와 리렌더링(re-rendering)
    • useEffect는 useEffect가 속한 컴포넌트가 화면에 렌더링 될 때 실행됩니다. 이런 useEffect의 특징에 의해 우리가 의도치않은 동작을 경험할수도 있다
    • 다음 코드를 보면 input이 있고 value라는 state를 생성하여 input과 연결시켰습니다. 이렇게 구현하고 브라우저에 input에 어떤 값을 입력하면 useEffect가 계속 실행되는 것을 볼 수 있습니다.
import React, { useEffect, useState } from "react";

const App = () => {
  const [value, setValue] = useState("");

  useEffect(() => {
    console.log("hello useEffect");
  });

  return (
    <div>
      <input
        type="text"
        value={value}
        onChange={(event) => {
          setValue(event.target.value);
        }}
      />
    </div>
  );
}

export default App;
  • 전체 흐름
    1. input에 값을 입력
    2. value, 즉 state가 변경된다
    3. state가 변경되었기 때문에, App 컴포넌트가 리렌더링 된다.
    4. 리렌더링이 되었기 때문에 useEffect가 다시 실행된다.
    5. 1번 → 5번 과정이 계속 순환한다.
  • 정리
    • 우리는 콘솔이 브라우저에 한번만 찍히길 원했지만, input을 입력할 때마다 계속 찍히고 있는 것 입니다. 하지만 이런 부분도 해결할 수 있습니다.

의존성 배열

  1. 의존성 배열(dependency array)이란?
    • useEffect에는 의존성 배열이라는 것이 있습니다. 쉽게 얘기하면 “이 배열에 값을 넣으면 그 값이 바뀔 때만 useEffect를 실행할게” 라는 것 입니다.
    // useEffect의 두번째 인자가 의존성 배열이 들어가는 곳 입니다.
    useEffect(()=>{
    	// 실행하고 싶은 함수
    }, [의존성배열])
    
  2. 의존성 배열이 빈 배열인 경우
    • 위에 보았던 코드와 동일한 코드 다만 useEffect에 의존성 배열만 추가
    • 일단 의존성 배열안에는 어떠한 값도 넣지 않았습니다. 의존성 배열이 “이 배열에 값을 넣으면 그 값이 바뀔 때만 useEffect를 실행할게” 라는 의미를 가진다고 했고 우리가 아무것도 넣지 않았으니 useEffect는 처음에 딱 한번만 실행되고 그 이후로는 어떤일이 일어나도 실행이 되서는 안됩니다.
    // src/App.js
    
    import React, { useEffect, useState } from "react";
    
    const App = () => {
      const [value, setValue] = useState("");
      useEffect(() => {
        console.log("hello useEffect");
      }, []); // 비어있는 의존성 배열
    
      return (
        <div>
          <input
            type="text"
            value={value}
            onChange={(event) => {
              setValue(event.target.value);
            }}
          />
        </div>
      );
    }
    
    export default App;
    

의존성 배열에 빈 배열[ ]을 넣은 경우

  • input에 어떤 값을 입력하더라도, 처음에 실행된 hello useEffect외에는 더 이상 실행이 되지 않는 것을 볼 수 있습니다. 이렇게 useEffect를 사용하는데, 어떤 함수를 컴포넌트가 렌더링 될때 단 한번만 실행하고 싶으면 의존성 배열을 [ ] 빈 상태로 넣으면 됩니다.
  1. 의존성 배열에 값이 있는 경우
    • 빈 배열을 넣었을 때, 최초 렌더링 이후에는 useEffect가 실행되지 않는다는 것을 보셨죠? 그럼 이제 의존성 배열에 value 를 넣어보겠습니다. 우리가 배운게 맞다면, value는 state이고 우리가 input을 입력할 때마다 그 값이 변하게 되니 useEffect도 계속 실행이 되겠죠?
    • 콘솔이 2번 찍혀 있는 것은 useEffect로 인해 두번 실행된 것이 아니라, strict mode 라는 개발 환경이라서 그렇게 보이는 것 입니다.

clean up

클린 업이란?

  • 우리가 처음에 “어떤 컴포넌트가 화면에서 사라졌을 때 무언가를 실행하고 싶다면” 이라는 소로 시작을 했습니다. 컴포넌트가 나타났을 때 (렌더링됐을 때 === 함수 컴포넌트가 실행됐을 때) useEffect의 effect함수가 실행되는 것은 우리가 배웠으니, 이제 컴포넌트가 사라졌을 때 무언가를 어떻게 실행는 과정을 클린 업(clean up)이라고 표현합니다.

클린 업 하는 방법

  • 클린 업을 하는 방법은 간단합니다. useEffect 안에서 return을 해주고 이 부분에 실행되길 원하는 함수를 넣으면 됩니다.
import React, { useEffect } from "react";

const App = () => {

	useEffect(()=>{
		// 화면에 컴포넌트가 나타났을(mount) 때 실행하고자 하는 함수를 넣어주세요.

		return ()=>{
			// 화면에서 컴포넌트가 사라졌을(unmount) 때 실행하고자 하는 함수를 넣어주세요.
		}
	}, [])

	return <div>hello react!</div>
};

export default App;

클린 업 활용해보기

  • 속세를 벗어나는 버튼을 만들었고 버튼을 누르면 useNavigate에 의해서 /todos로 이동하면서 속세 컴포넌트를 떠날 것 입니다. 그러면서 화면에서 속세 컴포넌트가 사라질 것 이고, useEffect의 return 부분이 실행 될 것 입니다.
import React, { useEffect } from "react";
import { useNavigate } from "react-router-dom";

const 속세 = () => {
  const nav = useNavigate();

  useEffect(() => {
    return () => {
      console.log(
        "안녕히 계세요 여러분! 전 이 세상의 모든 굴레와 속박을 벗어 던지고 제 행복을 찾아 떠납니다! 여러분도 행복하세요~~!"
      );
    };
  }, []);

  return (
    <button
      onClick={() => {
        nav("/todos");
      }}
    >
      속세를 벗어나는 버튼
    </button>
  );
};

export default 속세;
  • /에서 /todos 잘 이동했고, 그 과정에서 clean up이 실행되었습니다.
  • const nav = useNavigate(); ← 이 기능은 나중에 배울 기능입니다. 다른페이지로 이동해서 컴포넌트가 사라지고, 그에 따라 클린 업이 실행되는 과정에 집중해주세요

정리

useEffect는 화면에 컴포넌트가 mount 또는 unmount 됐을 때 실행하고자 하는 함수를 제어하게 해주는 훅이다.

의존성 배열을 통해 함수의 실행 조건을 제어할 수 있다.

useEffect에서 함수를 1번만 실행시키고자 할떄는 의존성 배열을 빈 배열로 둔다

알아보면 좋은 키워드

  • Strict mode란 무엇일까?
  • React라이프 사이클이란 무엇일까?
  • React에서 말하는 mount와 unmount란 무엇일까?

'IT > React' 카테고리의 다른 글

팀과제  (0) 2022.12.11
Redux  (0) 2022.12.08
컴포넌트 렌더링  (0) 2022.12.04
Props 란?  (0) 2022.12.04
State 란?  (0) 2022.12.04