[SeSAC Front-end] [React] Hooks 실습하기 (useState, useEffect, useRef)

Harimad·2022년 12월 5일
0

React

목록 보기
4/18
post-thumbnail

🌱 Intro

  • React의 Hook 중에 useState와 useEffect, useRef를 이용한 실습 문제를 풀어보도록 하겠습니다.
  • 문제를 풀면서 useEffect의 사용방법을 살펴보겠습니다.
  • useRef를 이용했을 때 어떠한 효과를 누릴 수 있는지도 알아보겠습니다.

🌱 본론


🔵 문제 1

🔵 풀이

  • 변수를 저장할 state를 하나 초기화 합니다.
  • input에서 onChange 이벤트가 발생할 때 value 값을 담을 state를 초기화 합니다.
  • inputHandler 함수를 정의합니다.
    • 이벤트가 발생하면 setValue 함수를 호출해서 value 값을 변경시킵니다.
    • 이 함수를 input 태그의 onChange 함수에 넣어줍니다.
  • clickHandler 함수를 정의합니다.
    • 이벤트가 발생되면 setState 함수를 호출해서 "value 값이 기존 state값 보다 선행하는 새 배열"을 state에 재할당 해줍니다.
import React, { useState } from 'react'

const App = () => {
  const [state, setState] = useState(['초콜렛', '사탕'])
  const [value, setValue] = useState('')

  const inputHandler = e => {
    setValue(e.target.value)
  }

  const clickHandler = e => {
    setState(prev => [value, ...prev])
  }

  return (
    <div>
      <input type={'text'} onChange={inputHandler}></input>
      <button onClick={clickHandler}>추가</button>
      <ul>
        {state.map((item, idx) => (
          <li key={idx}>{item}</li>
        ))}
      </ul>
    </div>
  )
}

export default App

🟡 문제 2

🟡 풀이

  • count와 text를 state로 초기화 합니다.
  • 버튼을 클릭했을 때 count를 1 증가시켜주는 countHandler 함수를 만들고 버튼의 onClick 이벤트에 넣어줍니다.
  • input에 입력했을 때 text의 값이 변경되도록 inputHandler 함수를 만들고 input 태그의 onChange 이벤트에 넣어줍니다.
  • useEffect함수를 호출합니다.
    • 첫 번째 인자는 콜백 함수를 넣습니다. 콜백 함수 안에는 출력하고 싶은 문자를 넣어줍니다.
    • 두 번째 인자는 빈 대괄호([ ])를 넣어서 처음 랜더링 될 때 콜백함수가 한번만 실행되도록 합니다.
import React, { useEffect, useState } from 'react'

const App = () => {
  const [count, setCount] = useState(0)
  const [text, setText] = useState('')

  const countHandler = e => {
    console.log('count 값이 변경되었습니다.')
    setCount(count + 1)
  }

  const inputHandler = e => {
    console.log('text 값이 변경되었습니다.')
    setText(e.target.value)
  }

  useEffect(() => {
    console.log('렌더링이 완료되었습니다.')
  }, [])

  return (
    <div>
      <h3>{count}</h3>
      <button onClick={countHandler}>+1</button>
      <hr></hr>
      <input type={'text'} onChange={inputHandler}></input>
      <h3>{text}</h3>
    </div>
  )
}

export default App

🟢 문제 3

Q. 문제점?

  • useEffect() 함수에서 두번째 인자에 [] 를 넣지 않으면, 리랜더링 되었을 때 useEffect() 함수안의 콜백함수가 재실행 됩니다.
  • 지금 useEffect() 함수안의 첫번째 인자로 setRenderCount() 함수가 호출됩니다.
  • 이 함수가 호출되면 페이지가 리랜더링 됩니다.
  • 그러면 또다시 useEffect() 함수가 실행되고, useEffect() 함수의 콜백함수인 setRenderCount() 함수가 재호출 됩니다.
  • 결국 useEffect()호출 -> setRenderCount()호출 -> useEffect()호출 -> setRenderCount()호출 ... 이 되면서 무한으로 랜더링 되는 버그가 발생하게 됩니다.

Q. 이를 방지하기 위해서는 어떤 조치를 취해야 할까요?

🟢 풀이

  • useEffect()함수의 두번째 인자로 대괄호([ ])를 넣어줍니다.
  • 대괄호 안에는 count 값을 넣어서 이 값이 바뀔 때만 useEffect()함수 안의 콜백함수가 재실행 되도록 합니다.
  • 그러면 버튼을 클릭할 때만 count 값이 변경되어서 useEffect()함수 안의 콜백함수가 실행됩니다.
  • 결국 무한으로 리랜더링 되는 것을 막을 수 있게 되었습니다.
import React, { useEffect, useState } from 'react'

const App = () => {
  const [count, setCount] = useState(0)
  const [renderCount, setRenderCount] = useState(0)

  useEffect(() => {
    setRenderCount(renderCount + 1)
    console.log('랜더링 완료')
  }, [count])

  return (
    <div>
      <h1>Count: {count}</h1>
      <h1>랜더링 횟수 : {renderCount}</h1>
      <button onClick={() => setCount(count + 1)}>Click</button>
    </div>
  )
}

export default App

🟣 문제 4

🟣 풀이

  • useRef()를 사용하면 input 태그에서 change 이벤트가 발생했을 때 state값이 변경되어서 페이지가 리랜더링 되는 것을 막을 수 있습니다.
  • 먼저 text 상태값을 초기화 합니다.
  • useRef()를 이용하여 textRef 변수를 초기화 합니다.
  • inputHandler 함수를 생성합니다.
    • 이 함수는 입력 이벤트가 발생했을 때 textRef.current 값이 동일하게 변경됩니다.
    • useRef()를 로 할당한 변수는 값이 직접적으로 바뀌어도 리랜더링이 되지 않습니다.
    • input의 onChange이벤트에 inputHandler 함수를 넣어줍니다.
  • clickHandler 함수를 생성합니다.
    • 클릭 이벤트가 발생하면 setText()함수를 호출합니다.
    • 인자로 textRef.current를 넣어줍니다.
    • setText() 함수는 페이지를 리랜더링 하는 기능을 가지고 있습니다.
    • button 태그의 onClick 이벤트에 clickHandler함수를 넣어줍니다.
  • input태그에 입력값이 들어가도 페이지는 리랜더링 되지않습니다.
  • 왜냐하면 useRef()를 이용한 변수 값이 바뀌기 때문입니다.
  • 버튼을 누를 때 setText() 함수를 호출하면서 리랜더링이 발생하게 되는데, 이때 textRef값이 화면에 보이게 됩니다.
import React, { useRef, useState } from 'react'

const App = () => {
  const [text, setText] = useState('')
  const textRef = useRef('')

  const inputHandler = e => {
    textRef.current = e.target.value
    // console.log(textRef.current)
  }
  const clickHandler = e => {
    setText(textRef.current)
  }
  return (
    <div>
      <input type={'text'} onChange={inputHandler}></input>
      <button onClick={clickHandler}>전송</button>
      <h3>전송된 단어 : {text}</h3>
    </div>
  )
}

export default App

🌱 나가면서

  • 문제를 풀어보면서 useState, useEffect, useRef의 기능을 알아보았습니다.
  • useState로 변수를 할당해서 state를 바꿔주는 함수를 호출하면, 페이지가 리랜더링 됩니다.
  • useEffect를 사용하면 첫번째 인자로 콜백함수를 넣습니다. 이때 두번째 인자를 비워두면, 페이지가 랜더링 될 때 콜백함수가 계속해서 호출되게 됩니다.
  • 자칫하면 무한으로 랜더링이 발생하는 문제가 생길 수 있습니다.
  • 가급적이면 두번째 인자에 대괄호([ ])를 넣어서, 페이지가 랜더링 되었을 때 한번만 콜백함수가 호출되도록 합니다.
  • 만약에 특정한 값이 바뀌었을 때만 콜백함수가 호출되게 하고싶다면, useEffect함수의 두번째 인자에 "[감시할 값]" 이런 방식으로 넣어주면 됩니다.
  • useRef를 사용해서 변수를 만들면, 이 변수에 값이 직접적으로 변경되어도 페이지가 랜더링 되지 않습니다.
  • 추가적인 내용은 참고란의 링크를 확인하시면 좋습니다.

🌱 참고


'새싹DT 기업연계형 프론트엔드 실무 프로젝트 과정 8주차 블로그 포스팅'
profile
Here and Now. 🧗‍♂️

0개의 댓글