React 16.8 gives developers much more freedom when it comes to functional components.

Small and lightweight functional components have only had a subset of the features available to components made with classes. That is until now. In addition to allowing state, functional components have access to the equivalent of component lifecycle methods as well. This allows the same amount of control while requiring less code.
In React 16.8 they added features that functional components have been lacking for quite some time. In addition, more functionality which have been the domain of 3rd party libraries such as Redux, also get baked right in.
This article will take a look at how to use state and lifecycle methods inside functional components to reduce the complexity and repetition of your code. In a later article I will also cover contexts and how to avoid prop drilling. Let’s get started.
State in Functional Components
Prior to React 16.8, if we wanted a component to have state it needed to be written as a class. Now we can use state in functional components as well. First you’ll need to import useState
from react
.
import React, { useState } from 'react';
useState
is a function. This is what we’ll need in order to add state to our functional component.
const [count, setCount] = useState(0);
useState
is called with the initial value that state should be set at. In the line above we’re setting our initial count value to 0
.
What is returned when we call useState
is an array where the first element is the value for state and the second element is a setter for it.
The example above uses Javascript array destructuring to set the state value to count
and the setter to setCount
.
Using State
When you want to use state you can just reference the value in the state variable you chose. In the above example it is count
. You can use it inside the JSX output of your function by simply using the curly braces: {count}
<p>Current Count: {count}</p>
In order to update our count we can just make a call to our setter setCount
.
<button onClick={ ()=> setCount(count + 1)}>Change Count</button>
So far an entire functional component with state looks like this:
import React, { useState } from 'react';
function Counter(){
const [count, setCount] = useState(0);
return (
<div>
<p>Current Count: {count}</p>
<button onClick={()=> setCount(count + 1)}>Change Count</button>
</div>
)
}
export default Counter;
Lifecycle Methods in Functional Components
In addition to state, we can also have the same control that we did with all those lifecycle methods only now in our functional components. Because it’s often required to duplicate code across several component lifecycle methods, React developers devised a clever, simpler system to use.
This is where we introduce useEffect
.
import React, { useEffect } from 'react';
The way to use this new function may not be entirely obvious at first but I’ll walk through the various ways to use it effectively.
The basic use case is here:
useEffect(()=>{
// This gets run as you would expect with componentDidUpdate
// and componentDidMount
})
Call useEffect
with the initial value you want your state to be. It takes care of all the code that you would normally put into the compontDidUpdate
and componentDidMount
methods but instead consolidates it into a single function thereby reducing the amount of code your application needs.
While this may be useful for most of your applications, if you only want to run code when a particular value changes then you can pass in a second parameter — an array with the state to watch. In addition, any stateful values your code needs to access should be passed in this way to ensure that your code has access to the latest value.
useEffect(()=>{
// This is run only when the values for state that are passed in change.
// All state used by this function must be passed in together
// to insure that it is current.
}, [someStateValue, someOtherStateValue])
Cleanup
Sometimes you need to do an action when your component unmounts such as remove listeners. useEffect
gives us a way to do this as well.
The function that is passed into useEffect
must either return a function or else nothing at all.
The returned function is only called when the component unmounts.
Here’s an example.
useEffect(()=>{
// This is called when the component updates.
return ()=>{
// This anonymous function gets called when the component will unmount.
// This is where you would remove any listeners etc...
}
})
Additional Features
In addition to adding features to functional components, React 16.8 takes aim at Redux by building within React ways to store state globally that prevent us from needing to prop drill down into deeply nested components.
The next article will go over how to use Context in React to replace the features of Redux.