You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
spa_instat_tv/src/hooks/useObjectState.tsx

36 lines
1.3 KiB

import type { Dispatch } from 'react'
import { useCallback, useState } from 'react'
import isFunction from 'lodash/isFunction'
type Updater<S> = (prevState: S) => Partial<S>
const isUpdater = <S extends object>(value: any): value is Updater<S> => (
isFunction(value)
)
/**
* Дженерик для создания типа сеттера, получает тип стейта как параметр
*/
export type SetPartialState<S> = Dispatch<Partial<S> | Updater<S>>
/**
* Хук на основе useState с возможносьтю мержа стейта как в классовых компонентах
*/
export const useObjectState = <S extends object>(initialState: S) => {
const [state, setState] = useState(initialState)
const setPartialState: SetPartialState<S> = useCallback((newStateOrUpdater) => {
setState((oldState) => {
const newState = isUpdater(newStateOrUpdater)
? newStateOrUpdater(oldState)
: newStateOrUpdater
// если updater функция вернула старый стейт то и здесь
// возвращаем тот же стейт чтобы избежать лишнего ререндера
if (newState === oldState) return oldState
return { ...oldState, ...newState }
})
}, [])
return [state, setPartialState] as const
}