DEV Community

Cover image for My 5 cents about React Hooks
Guilherme Toti
Guilherme Toti

Posted on

My 5 cents about React Hooks

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>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

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>
  )
}
Enter fullscreen mode Exit fullscreen mode

Can you see the difference? From 42 lines to 22 lines.
Basically, when you write:

const [data, setData] = useState({})
Enter fullscreen mode Exit fullscreen mode

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 })
Enter fullscreen mode Exit fullscreen mode

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>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

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>
  )
}
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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])
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
miketalbot profile image
Mike Talbot ⭐

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!

Collapse
 
guilhermetoti profile image
Guilherme Toti

IMHO, React Hooks forces developers to write "cleaner" code, using more function components instead of class components. It's awesome! Thanks for the comment!

Collapse
 
pabloabc profile image
Pablo Berganza

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

const [data, setData] = useState({})

You could do something like this

const [name, setName] = useState('')
const [email, setEmail] = useState('')

Since (as you saw), setState does not merge objects by default, it just replaces the whole state.

Collapse
 
guilhermetoti profile image
Guilherme Toti

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):

setData(data => ({ ...data, someUpdate: “ok” });

This way I get the current state value, add it to my object, and update what I want on it... keeping it immutable.

Collapse
 
drewkiimon profile image
Andrew Pagan

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?

Collapse
 
guilhermetoti profile image
Guilherme Toti

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.

Collapse
 
drewkiimon profile image
Andrew Pagan

That makes sense thank you! :)

Collapse
 
dragosnedelcu profile image
Dragos Nedelcu

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

Collapse
 
sphrases profile image
sphrases • Edited

Hi, I am interested about you guys oppinion on declaring props with function components:

const funComp = (props) => {
  //bla bla
  return <div>{props.someProp}</div>
}

const funComp = ({someProp}) => {
  //bla bla
  return <div>{someProp}</div>
}

I mainly use the first approach, but the second one is definitely "smarter". What do you think?

Collapse
 
slk5611 profile image
shivlal kumavat

I'm very clear by this article in React Hooks, Thank you.

Collapse
 
guilhermetoti profile image
Guilherme Toti

You’re welcome!