Hey there!
Welcome to my first post :D. In this post, I'm gonna introduce you to React Hooks, and then teach you two of the most used hooks - the state hook and the effect hook. Let's dive right in!
What are Hooks?
Hooks were introduced for the first time in React v16.8. They let you write components without using JavaScript classes. Which is actually really cool, because that means that you get to use state, lifecycle methods and other awesome things inside a regular JavaScript function!
Note: It's still absolutely fine to write class components. React has no plans to deprecate them as of now. But, Hooks are increasingly becoming the more effective way to write react code, so I'd suggest you try it out and I'm sure you'll get Hooked!
Let's look at a simple component coded using both class components and hooks:
// using Class Components
class CounterComponent extends React.Component {
constructor() {
super();
this.state = {
count: 0
};
}
componentDidMount() {
console.log("Component mounted");
}
componentDidUpdate(prevProps, prevState) {
console.log("Component rendered");
if (prevState.count !== this.state.count) {
console.log("current count is", this.state.count);
}
}
componentWillUnmount() {
console.log("Unmounting the component...");
}
render() {
return (
<>
<div>
<button
onClick={() => this.setState({ count: this.state.count + 1 })}
>
Increase
</button>
<button
onClick={() => this.setState({ count: this.state.count - 1 })}
>
Decrease
</button>
</div>
<div>
<p>Current count: {this.state.count}</p>
</div>
</>
);
}
}
// using Hooks
const Counter = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Component mounted");
}, []);
useEffect(() => {
console.log("Component rendered");
return () => console.log("Unmounting the component...");
});
useEffect(() => {
console.log("current count is", count);
}, [count]);
return (
<>
<div>
<button onClick={() => setCount(count + 1)}>Increase</button>
<button onClick={() => setCount(count - 1)}>Decrease</button>
</div>
<div>
<p>Current count: {count}</p>
</div>
</>
);
};
As we can see, the code written using hooks is much more concise, and we don't have to worry about 'this' anymore.
Why hooks?
React class components don't minify well, and this makes hot reloading unreliable. Minification of functions in Javascript is much better.
Also, the useEffect hook combines many lifecycle methods of class components like componentDidMount, componentDidUpdate and componentWillUnmount. Which means we don't have to split our work in different methods anymore.
With hooks, it becomes easy to reuse stateful logic, by making your own hooks, known as custom hooks.
React hooks make our code cleaner and shorter, which provides a good development experience!
The useState Hook
The purpose of this hook is to let you use state in functional components. The basic syntax of a useState declaration is:
const [count, setCount] = useState(0);
Here I have declared a state variable called count
and set it to 0. For updating username, we will call setCount
. UseState always returns two values, a state variable and a function to update it.
return (
<div>
<button onClick={() => setCount(count + 1)}>Increase</button>
<button onClick={() => setCount(count - 1)}>Decrease</button>
</div>
...
)
To display the state, we directly use count
:
return (
...
<div>
<p>Current count: {count}</p>
</div>
)
Whenever the user clicks on Increase or Decrease, setCount
updates count
with the new value, and React re-renders the component. Let's look at the complete component:
const Counter = () => {
const [count, setCount] = useState(0);
return (
<>
<div>
<button onClick={() => setCount(count + 1)}>Increase</button>
<button onClick={() => setCount(count - 1)}>Decrease</button>
</div>
<div>
<p>Current count: {count}</p>
</div>
</>
)
}
You can create multiple state variables, and use them as per your liking.
The useEffect Hook
This hook lets you use lifecycle methods like componentDidMount()
, componentDidUpdate()
and componentWillUnmount()
in functional components.
Let's take a look at a simple example:
useEffect(() => {
// This runs at the first render and after every render by default
console.log('Component rendered');
// This runs just before React unmounts the component
return () => console.log('Unmounting the component...');
})
If you want to control how many times a particular useEffect runs, you can specify a second argument, a dependency array, which is an array of values to it. The useEffect will run only when atleast one of the values in this array have changed since the last time. To demonstrate, we will take the help of our previous 'count' example. Let's see how this works:
useEffect(() => {
console.log('current count is', count)
}, [count])
If you pass an empty array, useEffect will run only once, on mount:
useEffect(() => {
console.log('Component mounted');
}, [])
You can view the full code on this codesandbox link.
To summarize, hooks are a powerful way to write your React code. To get started, you can start using hooks in the new components you make. Happy Coding!
Top comments (8)
Welcome great post. By the way you can use syntax highlighting in your code blocks to make them more readable github.com/adam-p/markdown-here/wi...
Great tip! I've implemented this in this post. Thanks a ton :)
What does useEffect with no dependency array means?
When are they used ?
Will it go to a state of infinite loop?
useEffect with no dependency array will run at the first render and after every render. It's used when we might want to run some code on every single render, although this scenario isn't used a lot.
No it won't go in a state of infinite loop unless you are changing any state values inside useEffect, in that case:
state change -> useEffect triggered -> state change -> ....goes on in an infinte loop
Empty array means only execute after mount. The value in the arrays is what react check for execution. Empty array means nothing to check
Hi Larrieu, I was referring to the scenario when we dont give a dependency array. 🙂
And one more doubt, why return a call back method inside the useEffect?
That's executed before the next useEffect, for example if you set a timeout inside useEffect, you must cancel it as return callback, so in the next execution, before setting the new timeout, the previously one is good to be cleared