useObject 👍
export function useObject<T>(
initialObject: T
): [
T,
(obj: Partial<T>, callback?: (state: T) => void) => void,
(e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => 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 | HTMLSelectElement>): 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>
)
}