관리 메뉴

공부기록용

ReactJS로 영화 웹 서비스 만들기(06/useEffect, cleanup ) 본문

📚강의록📚/노마드)React

ReactJS로 영화 웹 서비스 만들기(06/useEffect, cleanup )

과부하가즈아 2023. 7. 18. 15:50

https://nomadcoders.co/react-for-beginners/lobby

 

ReactJS로 영화 웹 서비스 만들기 – 노마드 코더 Nomad Coders

왕초보를 위한 React

nomadcoders.co


특정 코드의 실행을 제한하고 싶을때 useEffect를 사용하자.

import { useState } from "react";

function App() {
  const [counter, setCounter] = useState(0);

  function onBtnClick() {
    return setCounter((prev)=>{
      return prev +1
    })
  }
  console.log('i run all the time')
  
  return (
    <div>
      <h1>{counter}</h1>
      <button onClick={onBtnClick}>Click me!</button>
    </div>
  );
}

export default App;

> 버튼을 클릭해서 counter이 변하므로 렌더링이 발생하는 것은 맞지만 console.log('i run all the time')은 범위에 해당하지 않으므로 굳이 렌더링되지 않아도 되는 부분이다. 근데 계속해서 버튼을 누르면 같이 렌더링 되는 것을 볼 수 있다. 이때 불필요한 렌더링을 막기 위해서 useEffect( )를 사용한다. 

useEffect( )
// useEffect의 두번째 인자가 의존성 배열이 들어가는 곳 

useEffect(()=>{
	// 실행하고 싶은 함수
               }, [의존성배열])​

import { useState, useEffect } from "react";

function App() {
  const [counter, setCounter] = useState(0);


  function onBtnClick() {
    return setCounter((prev)=>{
      return prev +1
    })
  }
  console.log('i run all the time')
  
  
  const once=()=>{
    console.log('i run only once')
  }
  useEffect(once, [])


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

export default App;

> counter이 버튼의 클릭으로 값이 바뀌면 전체의 코드가 다시 또 리렌더링이 되어야 하지만 useEffect를 통해서 

console.log('i run only once')를 막아주어서 해당 내용은 최초 페이지의 렌더링 시에만 'i run only once'를 볼 수 있게 되었다. 

이렇게 바꿔줄 수 있다. 즉, useEffect는 지정한 코드가 한 번만 실행될 수 있도록 보호해주는 것이다.

(의존성 배열에 빈배열[ ]을 넣어줌으로써)

useEffect(() => {
  console.log('i run only once')
}, [])

input창에 값을 입력할 수 있게 하고, 그 값은 변하니까 state시키고

import { useState, useEffect } from "react";


function App() {
  const [counter, setCounter] = useState(0);

  const [keyword, setKeyword] = useState('');

  function onBtnClick() {
    return setCounter((prev)=>{
      return prev +1
    })
  }
  console.log('i run all the time')
  
  const onChangekeyword = (event) => {
    setKeyword(event.target.value)
  }

  useEffect(() => {
    console.log('i run only once')
  }, [])

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

export default App;

const [keyword, setKeyword] = useState('');

> 입력 내용을 keyword로 받고 그게 업데이트setKeyword된다

 

<input 
   value={keyword}
   onChange={onChangekeyword} 
   type="text" 
   placeholder="Search here..." />

> input창에 입력 내용은 keyword인거고 바뀔때마다_onChange 이벤트 발생

 

const onChangekeyword = (event) => {
  setKeyword(event.target.value)
}

> onChangekeyword() 함수를 실행할꺼다 

> onChangekeyword() 함수는 value를 뽑아와서 setKeyword가 되고 그 setKeyword는 결국의 최종 keyword이다. 

 

그래서 

 

> input에 onChange 이벤트가 발생하면 onChangeKeyword함수가 실행되서 value를 뽑아와 setKeyword로 넘겨서 결국 keyword가 되게 되는 것으로 값이 변하는 형태로써 렌더링이 발생하게 된다.

> 전체 코드의 실행으로 console.log('i run all the time')역시 렌더링되어 콘솔에 찍히는 것이고 이때, useEffect를 지정해 놓은 console.log('i run only once')를 제외하고 모든 코드가 실행되는 것이다. 


import { useState, useEffect } from "react";


function App() {
  const [counter, setCounter] = useState(0);

  const [keyword, setKeyword] = useState('');

  function onBtnClick() {
    return setCounter((prev)=>{
      return prev +1
    })
  }
  console.log('i run all the time')
  
  const onChangeKeyword = (event) => {
    setKeyword(event.target.value)
  }

  useEffect(() => {
    console.log('i run only once')
  }, [])
  
  console.log("SEARCH FOR", keyword)

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

export default App;
function onBtnClick() {
    return setCounter((prev)=>{
      return prev +1
    })
  }
  console.log('i run all the time')
  
  const onChangeKeyword = (event) => {
    setKeyword(event.target.value)
  }

  useEffect(() => {
    console.log('i run only once')
  }, [])
  
  console.log("SEARCH FOR", keyword)

> input에 값이 생기거나 click 이벤트가 발생되면

> console.log('i run only once')는 useEffect걸어두어서 콘솔에 출력X 

> console.log('i run all the time')와 console.log("SEARCH FOR", keyword)는 이벤트가 일어날 때마다 실행된다. 즉, 렌더링되어서 나타나 지는것이다. 

한번 더 체크 input에 값이 생기면 console.log("SEARCH FOR", keyword), 버튼이 클릭되면 console.log('i run only once') 만 렌더링 되게끔 하고 싶은 것


counter변화가 아닌 keyword의 변화시에만 console.log("SEARCH FOR", keyword)이 렌더링 되도록 하고 싶다.

useEffect(() => {
  console.log("SEARCH FOR", keyword)
}, [keyword])

> 의존성배열 자리에 [ ] -> 안에 들어가는 내용은 해당 내용이 변화할때마다 코드를 실행하겠다는 것으로 현재는 keyword가 변할때만 console.log("SEARCH FOR", keyword)를 실행하겠다는 의미이다.

> useEffect로 [keyword]넣어주니까 keyword가 변할때만 렌더링되고 그 외인 버튼 클릭시에는 console.log("SEARCH FOR", keyword)의 렌더링은 일어나지 않게 되었다.


추가로 keyword에 조건을 걸어주자

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

> keyword가 변화해서 해당 useEffect를 실행하는데

>> 만약 keyword가 빈 값이 아니고 5글자 이상일 경우("SEARCH FOR", keyword)를 출력해주겠다.


import { useState, useEffect } from "react";


function App() {
  const [counter, setCounter] = useState(0);

  const [keyword, setKeyword] = useState('');

  // 버튼클릭시
  function onBtnClick() {
    return setCounter((prev)=>{
      return prev +1
    })
  }
  
  // input 값 입력, 변화시
  const onChangeKeyword = (event) => {
    setKeyword(event.target.value)
  }

  // 맨 처음 렌더링 시
  useEffect(() => {
    console.log('i run only once')
  }, [])

  // counter변화시 -> 버튼 클릭시
  useEffect(() => {
    console.log("i run when 'counter' changes.")
  }, [counter])

  // keyword변화시
  useEffect(() => {
    console.log("i run when 'keyword' changes.")    
  }, [keyword])

  // counter와 keyword 중 하나라도 변하면 발생
  useEffect(() => {
    console.log("i run when 'keyword' & 'counter' changes.")    
  }, [counter, keyword])

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

export default App;

 

기본적으로 React는 새로운 데이터가 들어올 때 마다 UI를 렌더링한다 그래서 불필요한 소모가 많아지고 비효율적이다. 그래서 변화하지 않는 부분에 대해서 같이 렌더링되는 것을 막기 위해서 useEffect를 사용해서 조건을 걸어준다고 생각하면 된다. ([ ]에 들어간 부분의 값이 변한다면 조건을 실행하겠다.)


복습

import { useState } from "react";

function App() {

  const [showing, setShowing] = useState(false);

  function onClick(){
    setShowing(prev => !prev)
  }

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

}

export default App;

 


import { useEffect, useState } from "react";

function Hello(){

  useEffect(()=>{
    console.log("i'm here")
  }, [])

  return <h1>Hello</h1>
}


function App() {

  const [showing, setShowing] = useState(false);  

  function onClick(){
    setShowing(prev => !prev)
  }

  return <div> 

    <button onClick={onClick}>{showing ? "Hide" : "Show"}</button> 

    {showing ? <Hello /> : null}

  </div>; 

}

export default App;
return <div> 

  <button onClick={onClick}>{showing ? "Hide" : "Show"}</button> 

  {showing ? <Hello /> : null}

</div>;

> 초기 값이 false이니까 첫 렌더링 시 show가 보여지는 것 

 

function onClick(){
  setShowing(prev => !prev)
}

> 버튼을 클릭하면 onClick함수 작동으로 값이 반대로 ! 바뀌면서 setShowing -> showing으로 바뀐 값이 다시 셋팅 

> 그럼 true가 되고 

return <div> 

  <button onClick={onClick}>{showing ? "Hied" : "Show"}</button> 

  {showing ? <Hello /> : null}

</div>;

> Hide로 바뀌면서 

{showing ? <Hello /> : null}
function Hello(){

  useEffect(()=>{
    console.log("i'm here")
  }, [])

  return <h1>Hello</h1>
}

> showing의 true로 <Hello />실행 되니까 콘솔에 i'm here와 페이지에<h1>Hello</h1> 출력됨


cleanup 함수

컴포넌트가 destroy될 때도 코드를 실행할 수 있다.
-> return으로 함수를 만들어주면 된다. useEffect는 함수를 받고, 이 함수는 dependency가 변화할 때 호출됨

현재는 dependency가 비어있으니 컴포넌트가 처음 생성될 때 함수가 호출된 후 다시 호출 되지 않음 그래서 컴포넌트가 파괴될 때도 함수를 실행하고 싶으면 useEffect 함수가 새로운 함수를 return해야 함
-> 왜냐면 deps가 비어있으면 자동으로 컴포넌트가 파괴될 때 cleanup함수가 실행되는데 그 과정이 리렌더링으로 useEffect함수가 실행되고 클린업하면서 이전에 있던 이펙트인 console.log(“created :) )가 삭제되고 새로운 이펙트 함수인 return함수가 실행되기 때문이다.

리렌더링 -> 이전 이펙트 클린업 -> 이펙트 실행
function Hello(){

  useEffect(()=>{
    console.log("created :>");

    return function(){
      console.log("destoryed :<")
    }
  }, [])

  return <h1>Hello</h1>
}

해당 실행 함수가 언제 발생되고 사라지는지 알 수 있다. 

useEffect(function(){
  실행하고 싶은 함수(A.변경된 값이 화면에 나타날 때)
  
  return function(){
  	변경된 값이 화면에서 사라질 때 실행할 함수
  }
  
}, [이 값이 변경되면])

같은 결과1

function Hello(){
  
  // 함수가 사라질 때
  function destoryedFnc(){
    console.log("destoryed :<")
  }


  // 함수가 실행시
  function createdFnc(){
    console.log("created :>");
    return destoryedFnc;
  }

  useEffect(createdFnc, []);
  

  return <h1>Hello</h1>
}

> Hello는 [ ]가 바뀔때 실행_비어있는 관계로 처음 component가 생성될 때만(페이지의 첫 렌더링) Hello함수가 호출


같은 결과2

function Hello() {

  useEffect(() => {
    console.log("hi :)");
    return () => {
      console.log('bye:(')
    }
  }, []);

  return <h1>Hello</h1>;
}

//////////////////////////////

function Hello() {

  useEffect(function () {
    console.log("hi :)");
    return function(){
      console.log("bye :(");
    }
  }, []);

  return <h1>Hello</h1>;
}

 

Comments