Don't use useState directly when working with nested Object

But let you replace useState with a simple custom hook, and it would bring you much more fun and comfortable

·

2 min read

I used a lot of useState and feel uncomfortable when working with nested object in updating state. I wrote a simple custom hook that would let working with nested Objects be comfortable and easy. It's named useLocalComponentCache.

With the help of lodash library, updating an object becomes so easy. Let's get started.

Hook signature

Please note that init is optional. If you update a non-existed path, then it would be created automatically.

    const {
        localCache,
        handlers: {
            setLocalCache
        }
    } = useLocalComponentCache(init)

    //the signature of the function
    setLocalCache(value, path = "", toggle = false)

Sample object

const sampleObject= {
    background: {
        color: "#c69ef9",
        imgUrl: "/themes/simplicity/preview/callout-bg.svg",
        disabled: false
    },
    heading: {
        text: "Welcome to ProDesk",
        color: "#000000",
        size: {
            small: "10px",
            medium: "16px",
            large: "25px"
        }
    }
}

Usage

//change the heading text
setLocalCache("Welcome to my App", "heading.text")

//change the fontsize of medium
setLocalCache("15px", "heading.size.medium")

//add new value which not yet existed in init data
setLocalCache("40px", "heading.size.big")

//to toggle a value, we bypass the first parameter
setLocalCache(undefined, "background.disabled", true)

//or you can replace all with a completely new object
setLocalCache(newObject)

Note: to read the state, just read localCache directly as a normal object

The hook

Note: the hook uses lodash and react-use library for simple implementation.

import { get, set, cloneDeep } from "lodash"
import { useDeepCompareEffect } from "react-use"
...
export default function useLocalComponentCache(_object = {}) {
    const [cache, setCache] = useState(_object)

    useDeepCompareEffect(() => {
        setCache(_object)
    }, [_object])

    const handlers = React.useMemo(
        () => ({
            setLocalCache: (value, path = "", toggle = false) => {
                if (!path)
                    setCache(value)
                else
                    setCache(
                        (prevState) => {
                            let newCache = cloneDeep(prevState)
                            set(
                                newCache,
                                path,
                                toggle
                                    ? !get(prevState, path)
                                    : value
                            )
                            return newCache
                        }
                    )
            }
        }), [])

    return {
        localCache: cache,
        handlers
    }
}

Thank you for reading my very first article on the internet related to programming.

Code: gist.github.com/chasoft/78fcf8d922afb825664..

Have a nice day!