노마드코더 ReactJS로 영화 웹 서비스 만들기 6(useState)

딩쓰·2022년 12월 17일
0
post-thumbnail

#6.0~ 6.4

💡useState를 배우기전에 왜 필요한가부터 알아보자!

숫자 카운팅 페이지 만들기

//App.js
import { useState } from "react";

function App() {
  const [counter, setCounter] = useState(0); //0부터 시작
  const onClick = () => setCounter((prev) => prev + 1);

  console.log("render");
  return (
    <div>
      <h1>{counter}</h1>
      <button onClick={onClick}>click me!</button>
    </div>
  );
}

export default App;
  • button을 클릭하면 onClick함수가 실행되고 counter를 +1씩 해주는 컴포넌트를 만듬
  • CRA하기전 js파일에서는 React.useState() 이런식으로 앞에 React.을 작성해줬는데 생략이 가능해짐

But‼️ 여기서 문제가 있는데 state(counter)가 변할때마다 컴포넌트 전체가 리렌더링됨.

state가 변하면 전체가 리렌더링 되는 문제

  • 위에처럼 state(counter)가 변할때마다 code전체가 리렌더링되서 console.log('call an api') 도 계속 불러옴
  • 만약 실제로 API를 call을 해야하는 상황이 온다고 치면, 처음 한번만 API데이터를 받아도 되는데 state가 변화할 때마다 쓸데없이 API가 call 될거임

💡 어떻게 하면 component 내부의 특정 코드가 처음 한번만 실행되고, 다시는 실행되지 않도록 할 수 있을까? => useEffect를 사용하자!!

useEffect

import { useEffect, useState } from "react";

function App() {
  const [counter, setCounter] = useState(0);
  const onClick = () => setCounter((prev) => prev + 1);

  console.log("i run all the time"); //리렌더링 될때 마다 실행됨
  
  useEffect(() => {
    console.log("CALl THE API..");  //처음 한번만 렌더링 됨
  }, []);

  return (
    <div>
      <h1>{counter}</h1>
      <button onClick={onClick}>click me!</button>
    </div>
  );
}

export default App;
  • 리액트는 언제 코드를 실행할지 안할지 결정할 tool인 useEffect를 제공함
  • useEffect 함수는 우리 코드가 딱 한번만 실행될 수 있도록 보호해줌
  • useEffect(() => {}, []);
    • 두개의 인자가 있는데, 첫번째 arrument는 처음 한번만 실행하고 싶은 코드, 두번째 argumnt는 밑에서 배워보자

useEffect를 쓰는 이유?

글자를 타이핑 할 때마다 리렌더링 되는 문제
=> 사용자가 글자를 타이핑할 때마다 API를 새로 호출하면 비효율적임

function App() {
  const [counter, setValue] = useState(0);
  const [keyword, setKeyword] = useState('');
  const onClick = () => setValue((prev) => prev + 1);
  const onChange = (event) => setKeyword(event.target.value);
  
  console.log('i run all the time'); 
  
  useEffect(() => {
    console.log('CALL THE API...');
  }, []);
  
  return (
    <div>
      <input 
        value={keyword} 
        onChange={onChange} 
        type="text" 
        placeholder="Search here..." 
      />
      <h1>{counter}</h1>
      <button onClick={onClick}>click me!</button>
    </div>
  );
}
  • 위의 코드는 input의 value가 바뀔 때마다 리렌더링됨.

[]의 용도

function App() {
  const [counter, setValue] = useState(0);
  const [keyword, setKeyword] = useState('');
  const onClick = () => setValue((prev) => prev + 1);
  const onChange = (event) => setKeyword(event.target.value);
  
  console.log('i run all the time');
  
  useEffect(() => {
    console.log('CALL THE API...');
  }, []);
  
  useEffect(() => {
    console.log('Search for', keyword);
  }, [keyword]);
  //keyword가 바뀔때 마다 리렌더링 하고 싶으면 []안에 keyword를 적으면 됨.
    return (
    <div>
      <input 
        value={keyword} 
        onChange={onChange} 
        type="text" 
        placeholder="Search here..." 
      />
      <h1>{counter}</h1>
      <button onClick={onClick}>click me!</button>
    </div>
  );
}
  • []의 용도: 코드의 특정한 부분만이 변화했을 때, 원하는 코드들을 실행할 수 있는 방법
    즉, 위에선 keyword(movie state)가 변화할 때만 사용자가 원하는 영화를 검색하고 싶음.
  • useEffect(() => {}, []) 페이지가 처음 로드될 때 첫번째 argument가 실행된다음, []안의 state가 변화될 때도 첫번째 argument가 실행됨.
    • 만약 []이 빈칸이면 처음 한번만 렌더링됨.

사용자가 영화이름을 검색할때 예시

검색조건에 특정조건 주기

function App() {
  const [counter, setCounter] = useState(0);
  const [keyword, setKeyword] = useState("");
  const onClick = () => setCounter((prev) => prev + 1);
  const onChange = (event) => setKeyword(event.target.value);

  console.log("i run all the time");

  useEffect(() => {
    console.log("CALl THE API..");
  }, []);

  useEffect(() => {
    if (keyword !== "" && keyword.length > 5) {
      console.log("SEARCH FOR", keyword);
    }
  }, [keyword]);

  return (
    <div>
      <input
        value={keyword}
        onChange={onChange}
        type="text"
        placeholder="Search here..."
      />
      <h1>{counter}</h1>
      <button onClick={onClick}>click me!</button>
    </div>
  );
}

  • if (keyword !== "" && keyword.length > 5) 조건을 걸어서 조건이 충족되면 [keyword]가 변경되었을때 리렌더링 되게 할 수 있음.

Cleanup function 초기 셋팅

import { useState, useEffect } from 'react';

function App() {
  const [showing, setShowing] = useState(false);
  const onClick = () => setShowing((prev) => !prev);
  return (
  <div>
    <button onClick={onClick}>{showing ? "Hide" : "Show"}</button>
  </div>
  );
}

export default App;

  • Clean-up 함수란, useEffect()에서 parameter로 넣은 함수의 return 함수

clean function

show이면 Hello를 보여주기

function Hello() {
  return <h1>Hello</h1>;
}

function App() {
  const [showing, setShowing] = useState(false);
  const onClick = () => setShowing((prev) => !prev);
  
  return (
  <div>
    {showing ? <Hello /> : null} //js 쓸 때는 중괄호 쓰기
    <button onClick={onClick}>{showing ? "Hide" : "Show"}</button>
  </div>
  );
}

Cleanup 함수 생성


function Hello() {
  useEffect(() => {
    console.log("created :)");
    return () => console.log("destroyed :("); // cleanUp Function
  }, []);
  return <h1>Hello</h1>;
}

function App() {
  const [showing, setShowing] = useState(false);
  const onClick = () => setShowing((prev) => !prev);

  return (
    <div>
      {showing ? <Hello /> : null} 
      <button onClick={onClick}>{showing ? "Hide" : "Show"}</button>
    </div>
  );
}

  • 클린업 함수: 반환값에 반환 함수를 적어주는 것

클린업 함수 풀어서 적기

function Hello() {
  function byeFn() {
    console.log("bye :(");
  }
  function hiFn() {
    console.log("created :)");
    return byeFn;
  }
  useEffect(hiFn, []);
  return <h1>Hello</h1>;
}
  • 위에 처럼 풀어적을 수 있음
  • cleanup 함수는 보통은 사용하지 않고 정말 특정한때에 사용함.

최종코드

import { useEffect, useState } from "react";

function Hello() {
  useEffect(() => {
    console.log("hi :)");
    return () => console.log("bye :("); // cleanUp Function
  }, []);
  return <h1>Hello</h1>;
}

function App() {
  const [showing, setShowing] = useState(false);
  const onClick = () => setShowing((prev) => !prev);

  return (
    <div>
      {showing ? <Hello /> : null}
      <button onClick={onClick}>{showing ? "Hide" : "Show"}</button>
    </div>
  );
}

export default App;
profile
Frontend Developer

0개의 댓글