salsita / spicy-hooks

7 stars 0 forks source link

Add `core/useProperty` #26

Closed goce-cz closed 3 years ago

goce-cz commented 3 years ago

Signature

useProperty<O, K extends keyof O> (object: O, setObject: Dispatch<SetStateAction<O>>, property: K): [O[K], Dispatch<SetStateAction<O[K]>>]

Purpose

The purpose of this hooks is to select part of a complex state and work with it as if it is a simple one:

Usage example

const [object, setObject] = useState({ a: 'a', b: 1 })
const [b, setB] = useProperty(object, setObject, 'b')
...
return <button onClick={() => setB(prevB => prevB + 1)}>Increment B (current value: {b})</button>

Note that while in the above case it would be definitely better to allocate two different states, there are situations when you either cannot influence this (the object comes from above) or it is beneficial to use the object as an atomic unit.

Proposed implementation (untested)

export function useProperty<O, K extends keyof O> (object: O, setObject: Dispatch<SetStateAction<O>>, property: K): [O[K], Dispatch<SetStateAction<O[K]>>] {
  const setState = useCallback(
    (value: SetStateAction<O[K]>) =>
      setObject(prevCompositeState => {
        const previousValue = prevCompositeState[property]
        const newValue = isFunction(value)
          ? value(previousValue)
          : value
        if (newValue === previousValue) {
          return prevCompositeState
        }
        return {
          ...prevCompositeState,
          [property]: newValue
        }
      }),
    [setObject, property]
  )
  return [object[property], setState]
}

I'm looking forward to see 👍 / 👎 and eventual comments.

Fezzzi commented 3 years ago

I like the idea a lot! Furthermore, it would allow me to make some completely unrelated code much more readable 👍