React Conf 2018: Understanding React's hooks proposal with simple examples

Part of the Series:

Yesterday was the first day of the React conf, the community is very excited about the things that are happening with react (myself included), after watching some minutes of the conference we noticed a pattern, the word hooks started to be recurrent, and the more it was used the more amazed and hyped we were. In this article, we're going to be explaining how hooks work a little bit by identifying some key concepts and understanding a simple example of a counter that will be progressively evolving with the use of the different hooks (Ah, and you'll be reading the word hooks a lot). Grab a soda, fasten your seatbelt and enjoy the ride.

React Hooks are a new proposal available in the version 16.7.0-alpha of React and is currently being discussed in this RFC. Basically with the introduction of hooks you are no longer being forced to use classes just to be able to make use of react core features such as the state, yes, you read that correctly, you can now manipulate the state by using a function-based component, let me show you what I'm talking about with our first codepen example, take a look, don't panic, and then I'll explain what is going on, I promise, please don't panic:

I know, you're probably thinking: where is the setState call? where is my initial state property? is this real life? - the answers to these questions are very simple, we don't need the setState call nor the initial state property and yes, this is real life, we live in a world that's constantly changing and evolving (and to be honest, I love it).

The useState Hook

useState(initialState);

So, take a look at the code and check the beginning of the function, you see that useState call there? that ladies and gentlemen is a hook. As defined in the official documentation, a hook is a unique kind of function that allows us to "hook into" React features, it returns a pair representing the current state and a function that lets us update the state respectively, if you see the example, we're saving our current state in a variable called count and the update function in a variable called setCount, also notice how we're passing a 0 to useState, this is the initialization value that count will take. As you can see the initialization value can be different than an object on the contrary to setState, this also means that in case we wanted to update multiple types of values, the correct way to do it would be to call useState multiple times with the needed initialization values for each case.

useState key concepts

  1. It returns a pair, first returns the current state and second an updater function, you can easily assign these values by using array destructuring.
  2. It receives the initial state value as an argument, it doesn't necessarily have to be an object, it could be a number or string, depending on what is needed.
  3. To update multiple values, it's ok to call useState multiple times.
  4. Updating a state variable with useState always replaces the previous state, this is a key difference when compared to setState that merges states.
  5. It returns the same state value passed as an argument when the initial render happens.
  6. If it's called after the initial render, the first value returned will be the most recent after the executed updates.

The useContext Hook

useContext(ContextObject)

Allows us to access the context without having to introduce nesting to our component, you can avoid wrapping it into a provider and instead use the useContext hook that receives the context object as an argument, so, here the key concepts:

useContext key concepts

  1. It basically lets you subscribe to React's context without any nesting required.
  2. It receives a context object which is just the object returned from React.createContext().
  3. Triggers a rerender when the provider updates.

Here goes the same example of the counter but with an improved UI thanks to the useContext hook, check both code and the result:

Here we're just using the useContext hook to get the current theme and assign it to a variable, in this way we can access the properties (in this case the class property) and give some nice styling to our example.

The useEffect Hook

useEffect(() => {
    // Similar to componentDidMount
    // Subscribes, timers...

    return () => {
        // similar to componentWillUnmount
        // Clean subscriptions here.
    };
},
[FiringValues])

In the world of hooks, useEffect would be kind of the equivalent to what componenDidMount and ComponentWillUnmount combined are to a class-based component, in this hook is where you would usually handle side effects like mutations, subscriptions... and all the behaviors that could cause inconsistencies and unexpected errors in the interface. It runs after every completed render by default but you can make it fire only when some specified values change by passing a second parameter (array) to it. In case you want to clean up some subscriptions, you could do so by returning a function inside the first function passed to useEffect.

useEffect key concepts

  1. It Handles side effects, adds and cleans subscriptions.
  2. Runs after every completed render, we can limit it to fire only after certain specified values change.
  3. Receives two arguments, first a function and then an array of the values that will fire the hook.
  4. Returns a function inside the first function passed to handle cases in which we want to clean up some side effects.

Now an example, we'll use this hook to cast the window's width and reset the counter every time the width of the screen changes, for this we'll add and remove some listeners, let's take a look.

Excellent, so, let's explain a little. Here we're adding an effect to add and remove a resize event listener, this listener allows us to perform two operations, first it helps us clean the counter everytime the width of the screen changes and second it lets us set the current width into a state variable called width, which is then used to show the current screen width.

Custom Hooks

This one is very simple to explain, a custom hook is no more than a function that starts with the prefix use and that could make use of other hooks:

Custom hooks key concepts

  1. It's a good place to abstract reusable logic.
  2. Should start with the prefix use.
  3. Since it's defined by us, the function can have a customized signature and return values.

Now let's see an example, I'll refactor the example created for useEffect so that we can reuse the logic that sets the width of the screen, the functionality will be the same, but the code will be more flexible.

Now, let's analyze what we did here step by step.

  1. We're isolating the logic to set and get the width of the screen into a custom hook called useWindowWidth.
  2. We're returning the screen width from our custom hook in order to make it reusable.
  3. We're declaring a variable width to get the value returned by useWindowWidth.
  4. We're creating another useEffect hook inside our counter component, this allows us to reset the counter only when the screen width changes, this is possible because we're passing the second parameter to useEffect which is the property that will decide when to fire the updater.

Note: Maybe Another approach to avoid having an effect inside the component could be to pass the setCount updater to the useWindowWidth hook as an argument, the reason why I didn't go for this is because it will mean that all the functions that want to use useWindowWidth later will need to have the setCount function defined and having this limitation didn't convince me.

Some extra information that you should know about hooks is that they follow some rules and that there are many more to explore.

Boom!, did you like this new feature proposal so far? I'm loving it, have some fun playing around as I did and let me know in the comments if you enjoyed this article, as always you know you can contribute to the site on GitHub by sending a pull request, also, you can find me on twitter @duranenmanuel or email me at duranenmanuel@gmail.com.

See you in the next one developers of the future!

Want to leave a comment? Do it on twitter

Found something to fix in the article? Edit it and send a Pull Request on GitHub!

Want to be the first to receive our cool updates?

© Copyright EnmaScript 2023-2024. All code based on the MIT license.