Ever since hooks got introduced in React, it made it a lot more easier to handle
composition in react components and also helped the developers of react handle
the component context a lot better. Also, as consumers of the library, we could
finally avoid having to write this.methodName = this.methodName.bind(this)
which was a redundant part of the code to which a few developers ended up
writing their own wrappers around the component context.
Well, as developers there's always some of us who just go ahead follow the standard as is even when it makes maintenance hard and in case of hooks, people seem to just ignore the actual reason for their existence all together.
If you witnessed the talk that was given during the release of hooks, this post might be not bring anything new to your knowledge. If you haven't seen the talk
For the rebels, who are still here reading this, here's a gist of how hooks are to be used.
If you've not seen how hooks are implemented then to be put simply, the hook will get access to the component it's nested inside and has no context of it's own, which then gives you ability to write custom functions that can contain hook logic and now you have your own custom hook.
Eg: I can write something like this
import { useEffect, useState } from 'react'
function useTimer() {
const [timer, setTimer] = useState(1)
useEffect(() => {
const id = setInterval(() => {
setTimer(timer + 1)
}, 1000)
return () => clearInterval(id)
}, [timer, setTimer])
return {
timer,
}
}
export default function App() {
const { timer } = useTimer()
return <>{timer}</>
}
And that gives me a simple timer, though the point is that now I can use this timer not just in this component but any component I wish to have a timer in.
The advantages of doing this
This gives us smaller Component code to deal with while debugging.
Oh yeah, the original topic was about state... Now the other part of having
hooks is the sheer quantity that people spam the component code with it and
obviously the most used one is useState
.
As mentioned above, one way is to segregate it to a separate custom hook but if
you have like 10-20 useState
because you are using a form and for some weird
reason don't have formik setup in you codebase then you custom hook will also
get hard to browse through.
And, that's where I really miss the old setState
from the days of class
components and there's been various attempts at libraries that recreate the
setState as a hook and I also created one which we'll get to soon but the
solution is basically letting the state clone itself and modify just the fields
that were modified, not that hard right?
You can do something like the following
const [userDetails, setUserDetails] = useState({
name: '',
age: 0,
email: '',
})
// in some handler
setUserDetails({ ...userDetails, name: 'Reaper' })
And that works (mostly) but also adds that additional ...userDetails
everytime
you want to update state. I say it works mostly cause these objects come with
the same limitations that any JS Object has, the cloning is shallow and nested
states will loose a certain set of data unless cloned properly and that's where
it's easier to just use library's that make it easier for you to work with this.
I'm going to use mine as an example but you can find more such on NPM.
import { useSetState } from '@barelyhuman/set-state-hook'
import { useEffect } from 'react'
function useCustomHook() {
const [state, setState] = useSetState({
nested: {
a: 1,
},
})
useEffect(() => {
/*
setState({
nested: {
a: state.nested.a + 1
}
});
// or
*/
setState((prevState, draftState) => {
draftState.nested.a = prevState.nested.a + 1
return draftState
})
}, [])
return { state }
}
export default function App() {
const { state } = useCustomHook()
return <div className="App">{state.nested.a}</div>
}
and I can use it like I would with the default class styled setState
but if
you go through it carefully, I actually mutated the original draftState
and
that's because @barelyhuman/set-state-hook
actually create's a clone for you
so you can mutate the clone and when you return it still creates a state update
without actually mutating the older state.
useState
hooksmake it easier on your brain to read the code you write.