Hey guys, how are you doing?
I'll shortly tell about my experience with React Hooks.
Sometimes I accept external projects to work on and I use it as an opportunity to learn new things, test new stuff. Right now I'm working on a mobile project using React Native and I'm using this opportunity to learn React Hooks and Context.
At first time reading the React Hooks introduction, I was a bit confused about what is Hooks and how it works. So I decided to just jump in and try to use it.
What I've learn about it:
- React Hooks is a way to "shortener" your code
- Use more function components and less classes
- Easier to share and reuse stateful logic
Let's see those points in a real world.
React Hooks is a way to “shortener” your code
Lets say that you have a form and you need to store the form data and submit it when user click on the button. In a "not React Hooks" environment, would be something like:
import React from 'react'
class MyForm extends React.Component {
constructor(props) {
super(props)
this.state = {
data: {}
}
}
handleChange = (name, value) => {
const { data } = this.state
this.setState({
data: {
...data,
[name]: value
}
})
}
handleSubmit = (e) => {
e.preventDefault()
const { data } = this.state
MyAPI.doSomething(data)
}
render() {
const { data } = this.state
return (
<form onSubmit={this.handleSubmit}>
<input type="text" value={data.name} onChange={e => this.handleChange('name', e.target.value)} />
<input type="text" value={data.email} onChange={e => this.handleChange('email', e.target.value)} />
<button type="submit">Submit data</button>
</form>
)
}
}
This is how it will looks like using Hooks:
import React, { useState } from 'react'
const MyForm = () => {
const [data, setData] = useState({})
handleChange = (name, value) => setData(prev => ({ ...prev, [name]: value }))
handleSubmit = (e) => {
e.preventDefault()
MyAPI.doSomething(data)
}
return (
<form onSubmit={this.handleSubmit}>
<input type="text" value={data.name} onChange={e => handleChange('name', e.target.value)} />
<input type="text" value={data.email} onChange={e => handleChange('email', e.target.value)} />
<button type="submit">Submit data</button>
</form>
)
}
Can you see the difference? From 42 lines to 22 lines.
Basically, when you write:
const [data, setData] = useState({})
You are doing something like:
constructor(props) {
super(props)
this.state = {
data: {} // Initiating the data state as an empty object
}
}
render () {
const { data } = this.state // Getting the data key from state
}
AND
// Creating a kind of "helper" to set the state
const setData = data => this.setState({ data })
Use more function components and less classes
Using Hooks you don't need to have a lot of classes, you can do everything using function components!
Let's say that you need to track some props and do something if it changes. Without Hooks you would do something like:
import React from 'react'
class MyComponent extends React.Component {
componentDidUpdate(prevProps) {
if (this.props.name !== prevProps.name) {
console.log('NAME CHANGED')
}
}
render() {
const { name, email } = this.props
return (
<div>
<p>Your name is: {name}</p>
<p>Your email is: {email}</p>
</div>
)
}
}
In Hooks we use the useEffect function to do that:
import React, { useEffect } from 'react'
const MyComponent = ({ name, email }) => {
useEffect(() => {
console.log('NAME CHANGED')
}, [name])
return (
<div>
<p>Your name is: {name}</p>
<p>Your email is: {email}</p>
</div>
)
}
What i'm doing here:
useEffect(() => { // useEffect needs to receive a function as param
console.log(‘NAME CHANGED’) // Do something
}, [name]) // When the variable "name" changes.
I could also add another variable to the array, this would track it too, for example:
useEffect(() => {
console.log(‘NAME OR EMAIL CHANGED’)
}, [name, email]) // When the variable "name" OR "email" changes.
But in this case, I don't know which one changed. So, using Hooks you can separate it, you can have multiple useEffect:
useEffect(() => {
console.log(‘NAME CHANGED’)
}, [name])
useEffect(() => {
console.log(‘EMAIL CHANGED’)
}, [email])
And now you can do things separately depending on what variable changed.
Another important change using Hooks is the componentDidMount function. It is a function that executes once, usually to load data or set initial stuff.
Using Hooks there is a trick:
useEffect(() => {
console.log(‘I WILL APPEAR JUST ONCE’)
}, []) // Passing an empty array
Passing an empty array to the second param. This will be executed only once.
Easier to share and reuse stateful logic
Using Hooks you can extract the component logic to a custom hook and use it everywhere!
I won't talk about this topic with examples in this article because it can be very complex, so I do prefer to talk about it in another article.
But if you want to know more about it, you can check the documentation. It's awesome and very clear!
I'm enjoying using React Hooks so far. I had some trouble to understand it at the beginning but now it looks more clear to me.
I hope you guys enjoy my experience with Hooks and learn something from this.
If you have any question, please comment below! I'd be glad to help!
That’s all, folks!
Top comments (11)
I did a project in React a couple of years back and it was just so wordy, I didn't like it much. We came back to React as Hooks was in Beta. I don't have a single class component in the whole project (except external libraries) - I like React with Hooks, it makes sense to me and it's clean.
Great article!
IMHO, React Hooks forces developers to write "cleaner" code, using more function components instead of class components. It's awesome! Thanks for the comment!
The only thing I don't get is the following line with hooks
handleChange = (name, value) => setData(prev => ({ ...prev, [name]: value }))
I have to sometimes do this in
useEffect
to set a value properly. What exactly are we doing? Just using the previous value? When do you know when to do it exactly?When you use call the setter with a function as parameter, like you did, the “prev” (the function argument) is the current state.
In your example, the “prev” is the current value of “data”.
You usually do that way instead of just
setData(something)
when you probably have state changes with a very short period and you want to make sure you are using the latest state value possible.As setState is async, you may call it before other state change be completed and use old values. Using it with a parameter grants you using the latest state.
That makes sense thank you! :)
I agree with most.
Yet, they still give me a weird feeling, after more than a year using them.
The class decorator with all its "bads" was really explicit.
Onboarding new devs coming from another prog. languages or frameworks were so much easier.
Hooks are fantastic, yet way too 'implicit'.
Dragos
I've definitely enjoyed React much more since the introduction of Hooks!
Hey, I just have a minor nitpick! In your example of useState, you should generally avoid using an object. So instead of
You could do something like this
Since (as you saw), setState does not merge objects by default, it just replaces the whole state.
True, it replaces the whole state, but I do prefer to have an object on state instead N variables, (depending the case), but I think this is personal preferences.
When I set states with objects, I usually update it like (e.g):
This way I get the current state value, add it to my object, and update what I want on it... keeping it immutable.
Hi, I am interested about you guys oppinion on declaring props with function components:
I mainly use the first approach, but the second one is definitely "smarter". What do you think?
I'm very clear by this article in React Hooks, Thank you.
You’re welcome!