React is one of the most popular libraries for creating front end apps. It can also be used to create mobile apps with React Native.
In this article, we’ll look at some basic hooks that are built-into React to make our function components smart.
State and useState
We can use the useState
hook to store the state of our app. Therefore, it’s a basic building block of a smart React function component.
To use it, we write the following code:
import React from "react";
export default function App() {
const [count, setCount] = React.useState(0);
return (
<>
<button onClick={() => setCount(count => count - 1)}>decrement</button>
<p>{count}</p>
</>
);
}
In the code above, we have the count
state returned as the first element of the array returned by the useState
hook.
We then defined an onClick
handler which calls the setCount
function returned as the 2nd element in the array returned by useState
.
In there, we updated the count
by returning the existing count
value minus 1.
This lets us modify a state’s value based on its previous value. We can also pass in whatever we want to set directly if it doesn’t depend on the previous value of a state.
Passing in a callback will guarantee that the update is done based on the previous value of the state.
For instance, we can pass in a value directly into the state change function as follows:
import React from "react";
export default function App() {
const [text, setText] = React.useState("foo");
return (
<>
<button onClick={() => setText("foo")}>foo</button>
<button onClick={() => setText("bar")}>bar</button>
<button onClick={() => setText("baz")}>baz</button>
<p>{text}</p>
</>
);
}
In the code above, we have 3 buttons that have click handlers that call setText
to set the value of the text
state.
Since the value we set doesn’t depend on the previous value, we can just set it directly by passing in the value that we want to set the value of text
to.
The state change function can be used more than once, as we can see from the previous example.
It can accept any kind of value, including primitive values and objects.
Side effects and useEffect
The React useEffect
hook is another important hook that we can’t overlook.
It’s used to commit side effects like updating data asynchronously from an API or working with the DOM.
Side effects are actions that can change our component in an unpredictable fashion.
It accepts a callback function that is run during every render. To restrict the callback to run only when a specified value is changed, we pass in a second argument with an array of the value that we want to watch and run the callback when they change.
If we pass in an empty array as the 2nd argument, then the callback only runs when during the first render.
For instance, we can use it as follows:
import React, { useEffect } from "react";
export default function App() {
const [name, setName] = React.useState("");
const [data, setData] = React.useState({});
const getData = async () => {
const res = await fetch(`https://api.agify.io/?name=${name}`);
const d = await res.json();
setData(d);
};
useEffect(() => {
getData();
}, [name]);
return (
<>
<input value={name} onChange={e => setName(e.target.value)} />
<p>
{data.name} {data.age}
</p>
</>
);
}
In the code above, we have an input that changes the value of the name
state as we type something in it.
Then with the useEffect
hook, we watch for changes in name
so that getData
is called when the name
value changes.
In the getData
function, we call setData
to set the data and display the data that’s obtained from the API call.
We should just pass in an array as the 2nd argument always so that the callback won’t run during every render accidentally.
If we need to do clean up, we should return a function inside the useEffect
callback and run any cleanup code inside the callback if needed.
We can use add clean up code as follows:
import React, { useEffect } from "react";
export default function App() {
const [mousePosition, setMousePosition] = React.useState({});
const { x, y } = mousePosition;
const handleMouseMove = event => {
const { pageX, pageY } = event;
setMousePosition({
x: pageX,
y: pageY
});
};
useEffect(() => {
window.addEventListener("mousemove", handleMouseMove);
return () => window.removeEventListener("mousemove", handleMouseMove);
});
return (
<>
<p>
({x}, {y})
</p>
</>
);
}
In the code above, we added an event handler for the mousemove
event called handleMousemove
, which takes the mouse position and calls setMousePosition
to set the mousePosition
state.
We then watch the mouse position by writing:
window.addEventListener("mousemove", handleMouseMove);
in the useEffect
callback. Below it, we have:
return () => window.removeEventListener("mousemove", handleMouseMove);
to remove the mousemove
event listener when the App
component is no longer being rendered.
Conclusion
The useState
and useEffect
hook are the 2 most useful and basic hooks in the React standard library.
They let us update state and commit side effects respectively.