React Custom hooks 정확한 이해

Posted on Jan 10, 2023

그동안 리액트를 사용해 오면서, 기본 hooks를 이용하여 대부분의 로직을 수행했다. 하지만 반복되는 코드에 대해 항상 어떻게 하면 재사용성을 늘릴 수 있을까 고민 했었다.

커스텀 훅을 잘 사용하면 더 높은 레벨의 프론트엔드 개발자가 될 것 같았다.

커스텀 훅의 가장 중요한 원칙은 ‘값의 재사용이 아닌 로직의 재사용’ 이다.

훅 내부에 상태 변화에 대한 값만 매개변수로 지정해주어, Side effect에 따른 로직을 정해준다.

import { useState } from 'react'
function App() {
  const [inputValue, setInputValue] = useState('')

  const handleChange = (e) => {
    setInputValue(e.target.value)
  }

  const handleSubmit = () => {
    setInputValue('')
  }
  return (
    <div>
      <input value={inputValue} onChange={handleChange} />
      <button onClick={handleSubmit}>확인</button>
    </div>
  )
}

위의 코드를 custom hook으로 만들어보자.

import { useState } from 'react'

export function useInput(initialValue, submitAction) {
  const [inputValue, setInputValue] = useState(initialValue)

  const handleChange = (e) => {
    setInputValue(e.target.value)
  }

  const handleSubmit = () => {
    setInputValue('')
    submitAction(inputValue)
  }

  return [inputValue, handleChange, handleSubmit]
}
import { useInput } from 'hooks/useInput'

function displayMessage(message) {
  alert(message)
}

function App() {
  const [inputValue, handleChange, handleSubmit] = useInput(
    'Hello',
    displayMessage
  )

  return (
    <div>
      <input value={inputValue} onChange={handleChange} />
      <button onClick={handleSubmit}>확인</button>
    </div>
  )
}
import { useState, useEffect } from 'react'

const baseUrl = 'https://jsonplaceholder.typicode.com'

function App() {
  const [data, setData] = useState(null)

  const fetchUrl = (type) => {
    fetch(baseUrl + '/' + type)
      .json()
      .then((res) => {
        setData(res)
      })
  }

  useEffect(() => {
    fetchUrl('users')
  }, [])

  return (
    <div>
      <button onClick={() => fetchUrl('users')}>Users</button>
      <button onClick={() => fetchUrl('posts')}>Posts</button>
      <button onClick={() => fetchUrl('todos')}>Todos</button>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  )
}

위의 코드를 custom hook을 이용한 로직으로 바꿔보자.

import { useEffect, useState } from 'react'

export function useFetch(baseUrl, initialType) {
  const [data, setData] = useState(null)

  const fetchUrl = (type) => {
    fetch(baseUrl + '/' + type)
      .json()
      .then((res) => {
        setData(res)
      })
  }

  useEffect(() => {
    fetchUrl(initialType)
  }, [])

  return {
    data,
    fetchUrl,
  }
}
import { useFetch } from 'hooks/useFetch'

const baseUrl = 'https://jsonplaceholder.typicode.com'

function App() {
  const { data, fetchUrl } = useFetch(baseUrl, 'users')

  return (
    <div>
      <button onClick={() => fetchUrl('users')}>Users</button>
      <button onClick={() => fetchUrl('posts')}>Posts</button>
      <button onClick={() => fetchUrl('todos')}>Todos</button>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  )
}
import { useFetch } from 'hooks/useFetch'

const baseUrl = 'https://jsonplaceholder.typicode.com'

function App() {
  const { data: userData, fetchUrl } = useFetch(baseUrl, 'users')
  const { data: postData, fetchUrl } = useFetch(baseUrl, 'posts')
  const { data: todoData, fetchUrl } = useFetch(baseUrl, 'todos')

  return (
    <div>{userData ? <pre>{JSON.stringify(userData[0], null, 2)}</pre> : null}</div>
    <div>{postData ? <pre>{JSON.stringify(postData[0], null, 2)}</pre> : null}</div>
    <div>{todoData ? <pre>{JSON.stringify(todoData[0], null, 2)}</pre> : null}</div>
  )
}
comments powered by Disqus