In my first post in this series I said:
we'll be needing to use a class later, to get access to states
It turns out I was wrong. This was once the case but the React team have remedied it with Hooks
. I discovered Hooks
thanks to this post.
React Hooks: Implementation of useState
josesrodriguez610 γ» Jul 13 '20
What are Hooks
?
Let's look at how the React documentation describes Hooks
.
A
Hook
is a special function that lets you βhook intoβ React features. For example,useState
is aHook
that lets you add React state to function components.
Converting Classes
I'm going to convert my old class
, MaterialSwitch, from React: A simple start into a functional component. It will work exactly the same but, should, use less code and run a little quicker (as it doesn't have to load in all of React)
Render
Our old render function will become our whole MaterialSwitch function.
render() {
const {children, readOnly, disabled, defaultChecked } = this.props;
return (
<label className="md_switch">
<input
readOnly={readOnly}
disabled={disabled}
defaultChecked={defaultChecked}
onChange={this.changeHandler}
type="checkbox"
/>
<span className="md_switch__toggle"></span>
{children}
</label>
)
}
Because we're now using a function
and not a class
we need to pass in props
and this.props
will become props
but that's all we need to worry about right now.
function MaterialSwitch(props) {
const {children, readOnly, disabled, defaultChecked } = props;
return (
<label className="md_switch">
<input
readOnly={readOnly}
disabled={disabled}
defaultChecked={defaultChecked}
onChange={this.changeHandler}
type="checkbox"
/>
<span className="md_switch__toggle"></span>
{children}
</label>
)
}
Constructor
The constructor this contains super
, default states and the binding of this
to a function. We don't need any of these so let's delete that.
constructor(props) {
super(props);
this.state = {
checked: props.defaultChecked
}
this.changeHandler = this.changeHandler.bind(this);
}
We do still need to do something with the state though, so let's look at useState
. useState
is a function that returns two values, a reference to the current state and a function to update it. Because it returns two values we'll use destructuring assignment to save those values.
The naming convention that is most common, for our two values, is [stateName, setStateName]
. Which will leave us with stateName
containing the value and setStateName
being the function to update it.
The last thing to note about the useState
function is that it takes one argument, the default/initial state. Now we know all that we can boil our checked
state down to this, which will appear in the function.
function MaterialSwitch(props) {
const {children, readOnly, disabled, defaultChecked } = props;
// This is our new line
const [checked, setChecked] = React.useState(defaultChecked);
return (
<label className="md_switch">
<input
readOnly={readOnly}
disabled={disabled}
defaultChecked={defaultChecked}
onChange={this.changeHandler}
type="checkbox"
/>
<span className="md_switch__toggle"></span>
{children}
</label>
)
}
Functions
We only had one function in the class
version but we'll still need to move that into our new main function.
changeHandler(event) {
const { onChange } = this.props;
this.setState({checked: event.target.checked});
If(typeof onChange === "function") onChange(event);
}
As we know this.setState();
becomes setStateName();
, onChange
needs to be declared when we declare all our props
and the reference to changeHandler
drops the this
but that's it.
function MaterialSwitch(props) {
// We added onChange to this line
const {children, readOnly, disabled, defaultChecked, onChange } = props;
const [checked, setChecked] = React.useState(defaultChecked);
// Here is our function
const changeHandler = function(event) {
setChecked(event.target.checked);
if(typeof onChange === "function") onChange(event);
}
return (
<label className="md_switch">
<input
readOnly={readOnly}
disabled={disabled}
defaultChecked={defaultChecked}
// We had to change this reference to the function too
onChange={changeHandler}
type="checkbox"
/>
<span className="md_switch__toggle"></span>
{children}
</label>
)
}
And that's everything moved over. The original class
version was 35 lines of code and this, new, functional
version is only 24. Shaving off 11 lines of code might not seem like a lot but it soon adds up.
Wrapping up
And there we have it, what started as a gap in my knowledge became a great learning experience, there is much more for me to learn about hooks and I'm sure I'll cover what I learn in the future.
Thank you so much for reading and, as always, feel free to post questions or corrections in the comments below. If you have any posts you want me to read feel free to post them too, I'm always interested to see other stuff. Thanks again!
π¦π§ ππ¦π¦πβ€π§ πβ€
Top comments (7)
Hey @link2twenty , nice article. One quick doubt though, How to initialise multiple state values?
A component may require more states, like we have seen in case of Class components.
That's a very good question and there are two ways to have multiple state values.
This way will create multiple variables and functions that can all be called, it generally the way React suggest doing it.
The other way is to have one state that is an object, this makes setting the state a little different as I'll show you.
Personally I prefer the simplicity of the first approach.
Hey @link2twenty , a follow-up question, if we do go ahead with the first approach that you just showed, won't it have a performance impact? Consider the following:
Now if we get a fresh quote in
useEffect(...)
and I update both quote and author on success, won't it cause 2 re-renders due to 2 set states?Funnily enough, I was actually looking into this last night. I'd read a few places that several sets together sort of roll into one to save rendering lots. So I've made this quick proof of concept.
The number will go up each time we run render (based on either of those states changing).
Thanks for the explanation. Yes, The first approach seems a lot more readable. Simplicity over everything else! π
Lovely more of this thanks
Thank you for reading π