DEV Community

loading...

React Hooks (useContext, useEffect, useState, useRef) Summarized Like Crazy (Short & Concise Article).

ishakmohmed profile image Mohmed Ishak Updated on ・4 min read

Hey React engineers! In this article, I'll explain the 4 most important hooks you need to know in React. Don't worry, I'll not write a long essay and bore you. If you love simplistic articles that get straight to the point, this is the article you need to understand these hooks.

[1] useState

The simplest of the 4 hooks I'm going to explain in this article. useState allows you to have a state variable in functional component. If you're confused, it's just a normal variable which can make a component re-render when the value of the variable is changed (to be exact, in most cases). For example:

import { useState } from "react";

function demo() {
  const [isVisible, setIsVisible] = useState(true);

  return <>{isVisible && <h1>I'm visible</h1>}</>;
}

export default demo;
Enter fullscreen mode Exit fullscreen mode

Use useState in functional component. The argument (initial value) can be anything, such as numbers, boolean values, etc. In this case, true (boolean). Doing this gives us two things in an array, the first is the actual variable itself and then a function to update the value of that variable. In this case, we're destructuring the two values right away which is the convention. Now, it's just a normal variable. To set its value use the dedicated function that we destructured earlier like this:

setIsVisible(false);
Enter fullscreen mode Exit fullscreen mode

That's it. The only special thing to note is that state variables allow you to re-render components upon change of data (in most cases).

[2] useEffect

Used in one of the following two cases. One is to trigger something when the function it is in is rendered. Another is to trigger something when a specific data it is assigned to keep an eye on is changed.
Case 1:

import { useEffect } from "react";

function demo() {
  useEffect(() => {
    console.log("Like my post!");
  }, []);
}

export default demo;
Enter fullscreen mode Exit fullscreen mode

Please take note that the second argument is array of dependencies. In this case useEffect is not keeping an eye on any data, thus it will not get executed (except for the first time this component is rendered). Therefore, we'll only see "Like my post!" in console for the first time.

Case 2:

import { useEffect } from "react";

function demo() {
  const data = [1, 2, 3];

  useEffect(() => {
    console.log("Like my post!");
  }, [data]);
}

export default demo;
Enter fullscreen mode Exit fullscreen mode

In this case, useEffect is keeping an eye on variable called data. Therefore, if you change this data a million times, you'll see "Like my post!" in console a million times.

Edit: credits to Harsh Wardhan from comment section below because he suggested me to add the 3rd case for useEffect, which is the cleanup function. Basically, just before the last right curly brace in useEffect, you can write a "return" keyword followed by function used to do cleaning up. For example, maybe you've got a timer in useEffect that is used to refresh a component, say every 5 minutes. When the component is unmounted, you need to stop that timer, otherwise there's going to be a memory leakage. By the way, the equivalent of this in class component is componentWillUnmount(), which basically means if the component will unmount, clean it up (of course you need to implement the cleaning logic yourself).

[3] useContext

What this hook means is that you can send a data from a component to all child components. Now, all child components are ELIGIBLE to get that data and if they want to, the child components may choose to consume that data using useContext. Example:

const whateverContext = React.createContext();

<whateverContext.Provider value={whateverValue}>
   <>
     <ChildComponent1 />
     <ChildComponent2 />
     <ChildComponent3 />
   </>
</whateverContext.Provider>
Enter fullscreen mode Exit fullscreen mode

Here, after creating the context, the parent component wraps the child component (make sure to append .Provider to provide data to child component) and passed whateverValue as the value. At this point, all child components are ELIGIBLE to get the data. Let's assume ChildComponent3 wants to consume the data. Here's how it would do that:

const whateverValue = useContext(whateverContext);
Enter fullscreen mode Exit fullscreen mode

That's it. Basically, useContext is an elegant solution instead of prop drilling. Please take note that useContext is NOT a replacement to Redux. The reason will be explained in upcoming post. However, be assured that you can build pretty much any application easily by using useContext.

[4] useRef

Everyone talks about it, no one really uses it. First, let's look at the problem:

<ScrollView onContentSizeChange={() => }>
// ...
</ScrollView>
Enter fullscreen mode Exit fullscreen mode

Now, for whatever reason, we've got a component named ScrollView with incomplete onContentSizeChange() attribute. The challenge is,
inside onContentSizeChange(), we need to reference this ScrollView and invoke a function called scrollToEnd(). How can this component refer itself? I guess useRef would help. Here's the solution:

function abc() {
  const scrollView = useRef();

  return (
    <View>
      <ScrollView
        ref={scrollView}
        horizontal
        onContentSizeChange={() => scrollView.current.scrollToEnd()}
      >
// ...
Enter fullscreen mode Exit fullscreen mode

See, first useRef was called and the output was given a value called scrollView. Then, ScrollView component is connected with the scrollView reference from useRef (ref={scrollView}). Finally, now that we've got a reference to this component and connected it, we can call the function we wanted to inside onContentSizeChange, and that is scrollView.current.scrollToEnd(), where current references the current ScrollView component.

That's it. If you find this informative, please give this article a like as I've spent an hour writing it (had to review my notes).

Discussion (35)

Collapse
vnankov profile image
Valentin Nankov

Can you clarify the ref hook? From your example I am confused, does the ref help us to make an instance to this same component ( something like new keyword )? Or the ref just give us the access to the current keyword (currently visible DOM element) and nothing more?
Other than that, very good explanation, thank you!

Collapse
ishakmohmed profile image
Mohmed Ishak Author • Edited

Short answer: useRef refers to an object and the .current property allows you to access its instance. It is what you do with useRef that matters.

The core usage of useRef hook is to store reference of element.

function TextInput() {
  const theInput = useRef();

  const onClick = () => {
    theInput.current.focus();
  };

  return (
    <>
      <input ref={theInput} type="text" />
      <button onClick={onClick}>
        CLICK ME TO FOCUS IN THE INPUT WITHOUT CLICKING THE INPUT ITSELF BUT ME,
        THE BUTTON!
      </button>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

What's happening in this code snippet above is that we've got a text input and right below that a button. We know that the text input will get focused when clicked but that is not the concern here. The challenge is to focus the text input when the button (another element) is clicked. How?

There are just 3 easy steps you need to follow. First, call useRef and get the value, in this case "theInput". Then we need to connect that value to any element, in this case the input element by writing (ref={theInput}). At this point, "theInput" and element in connected, or in other words, "theInput" now refers the input element. Finally, we can change the state of the input element to be focused, because we've got a reference to it using theInput.current.focus().

Collapse
mrtnbroder profile image
Martin Broder • Edited

I'm sorry but that's bollocks. useRef has nothing to do with the DOM. It's stated clearly on the offical docs:

useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.
Enter fullscreen mode Exit fullscreen mode

Please don't spread false information.

useRef is useful whenever you want to reference the same value on every render, but not trigger a re-render when its value changes.

Thread Thread
hcbartelt profile image
Hans Christian Bartelt

That's it. Thank you 👍

Thread Thread
ishakmohmed profile image
Mohmed Ishak Author • Edited

@mrtnbroder apparently you're right, my bad. I just need to remove the "DOM" part in that comment, will edit it now. That's how I always understood the useRef hook. Thanks dude.

Collapse
vnankov profile image
Valentin Nankov

Thank you very much for the clarification! So in other words useRef is like querrySelector function in the pure JS way. Please correct me if I am wrong.

Thread Thread
ishakmohmed profile image
Mohmed Ishak Author

You're right. Not to worry, usually you don't need it.

Thread Thread
moustachedsign profile image
Moustache Design

yes, the difference is querySelector is imperative, useRef declarative, also querySelector does a search for the string you pass to it, so you have to know that is unique and won't change.
useRef on the other hand, ties itself to that jsx element and nothing else.

Thread Thread
ishakmohmed profile image
Collapse
rachelnabors profile image
Rachel Nabors

Nice write up! To clarify, the only way to trigger a render is to use the state setting function (ie setState()). If you update the state variable any other way, it not only won't trigger a rerender, but if something ELSE triggers that rerender, if your variable is a primitive like boolean, number or string, you'll lose your changes with the rerender!💜

Collapse
ishakmohmed profile image
Mohmed Ishak Author • Edited

Yes, totally forgot that. Thanks for reminding me. I'll edit the article. 😄

Collapse
hw_tech profile image
Harsh Wardhan

I would suggest to add Case 3 for useEffect() hook mentioning clean-up function (the return function). Use case example: When you need to refresh a particular component let's say every 5 minutes then you would set the interval in useEffect as usual but to clear the interval which should be done in this clean-up return function (similar to componentWillUnmount class component lifecycle method). I'd recommend a short article on this, by Martín Mato - dev.to/otamnitram/react-useeffect-...

Overall, nice and concise article. Thanks for this quick read!

Collapse
ishakmohmed profile image
Mohmed Ishak Author

Thanks bro, I'll add it to my article.

Collapse
kevinrobert3 profile image
kevinrobert3

Nice.. can you do one on creating custom hooks 🪝

Collapse
ishakmohmed profile image
Mohmed Ishak Author

Bro, I wanted to write an article on this, but I stumbled upon a pretty good article on how to create custom hooks, here you go: dev.to/keyurparalkar/creating-cust...

Collapse
ishakmohmed profile image
Mohmed Ishak Author

I've made a bunch of custom hooks that work well without overcomplicating stuffs. Next post will be about that. Follow me so that you don't miss that post.

Collapse
esbblo profile image
Esbjörn Blomquist

You could simplify
return <>{isVisible && <h1>I'm visible</h1>}</>;
to
return isVisible && <h1>I'm visible</h1>;

and I think this is a syntax error:
<ScrollView onContentSizeChange={() => }>

Collapse
ishakmohmed profile image
Mohmed Ishak Author

Yes could've simplified that one. As for the syntax error, it's not a syntax error, but just the opening tag of ScrollView component in React Native. I wrote "//..." below that line to indicate that more content is expected in the code snippet but that content doesn't matter for the tutorial. I hope we're friends now hehehehh.

Collapse
cutioluis profile image
Luis Cutiopala

What do you think of Hook useReducer?

Collapse
ishakmohmed profile image
Mohmed Ishak Author

I've never used it. 😄

Collapse
cazterk profile image
Cephas Zulu

Interesting article

Collapse
ishakmohmed profile image
Collapse
mateusmarquezini profile image
Mateus Marquezini

nice post, man! Thank you! :)

Collapse
ishakmohmed profile image
Mohmed Ishak Author

Thanks man. 😃

Collapse
sgnilreutr profile image
sgnilreutr

Always nice to read so much information laid out clear and concise.

Collapse
ishakmohmed profile image
Collapse
codemasteric profile image
Felix Onen

Nice article, simple and precise. thanks

Collapse
ishakmohmed profile image
Mohmed Ishak Author

Glad you liked it.

Collapse
ashish40781304 profile image
Ashish

Nice explaination of hooks 👍👍

Collapse
ishakmohmed profile image
Mohmed Ishak Author

Thanks dude!

Collapse
delacernamarimar profile image
Marimar Dela Cerna

Great this is very helpful

Collapse
ishakmohmed profile image
Mohmed Ishak Author

Thank you, give it a like!

Collapse
gabrieljosehernandez profile image
Gabriel Hernández

Very concise & helpful to read, thanks for the great post, looking foward to see your article about why usecontext + usereducer are not a subtitute for redux.

Collapse
ishakmohmed profile image
Mohmed Ishak Author

Thanks man. Appreciate that. 😄

Forem Open with the Forem app