직접 만들어서 쓰는 Hooks들

2021. 03. 13

useObject 👍

export function useObject<T>(
  initialObject: T
): [
  T,
  (obj: Partial<T>, callback?: (state: T) => void) => void,
  (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void,
  (keys?: Array<keyof T>) => void
] {
  const [state, setState] = useState<T>(initialObject)
  const callbackRef = useRef<(state: T) => void>()
  const isFirstCallbackCall = useRef<boolean>(true)
  const onChange = useCallback(
    (obj: Partial<T>, callback?: (state: T) => void) => {
      callbackRef.current = callback
      setState((prevState) => ({ ...prevState, ...obj }))
    },
    [state]
  )
  const onEventChange = useCallback(
    ({
      target: { name, value }
    }: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>): void =>
      setState((prevState) => ({ ...prevState, [name]: value })),
    [state]
  )
  const arrayToObject = (keys: Array<keyof T>): T => {
    if (!keys.length) return initialObject
    const initial: any = {}
    keys.reduce((acc, cur) => (initial[cur] = ''), initial)
    return initial
  }
  const onResetState = (keys?: Array<keyof T>) =>
    setState(keys ? arrayToObject(keys) : initialObject)
  useEffect(() => {
    if (isFirstCallbackCall.current) {
      isFirstCallbackCall.current = false
      return
    }
    callbackRef.current?.(state)
  }, [state])
  return [state, onChange, onEventChange, onResetState]
}

객체 형식의 state를 다룰 때 필수로 사용합니다. 이 훅스 하나로 한 컴포넌트의 모든 상태를 다 관리할 수 있습니다.

예제

import React from 'react'
import { useObject } from 'services'

interface State {
    email: string
    password: string
    loading: boolean
}

const Component = () => {
    const [{ email, password, loading }, setState, onChange, onResetState] = useObject<State>({
        email: '',
        password: '',
        loading: false
    })

    const onSubmit = async (e: ChangeEvent<HTMLFormElement>) => {
      	e.preventDefault()
          setState({ loading: true }, state => console.log(state))
          await login({ email, password })
      	...
    }

    return (
        <form onSubmit={onSubmit} >
            <input value={email} name="email" onChange={onChange} />
            <input value={password} name="password" onChange={onChange} />
            <button type="submit">로그인</button>
            <button onClick={() => onResetState()}>모든 State 초기화</button>
            <button onClick={() => onResetState(['state1', 'state2'])}>특정 State 초기화</button>
        </form>
    )
}

개발 블로그

김동욱

wcgo2ling@gmail.com

© 2021 kidow. All right reserved.