
React Hooks – useState and useEffect
tl;dr
Demo for react hooks usage – useState
and useEffect
. As I found out I haven’t write any post about the React Hooks yet. 😅
The first thing I look into React Hooks is the ability to reuse stateful logic (At that time, I haven’t familiar with the concept of Higher order Component
yet.) Thus, I’m excited for the React Hooks where I found it can reduce a lot of repeated stateful logic.
Introduction
React Hooks was introduced in version 16.8. It allow you to interact with state
in functional component.
#1 useState
@ Example 1
import React, { useState } from 'react';
function Example() {
const [value, setValue] = useState(0);
}
@ Example 2
import React from 'react';
function Example() {
const [value, setValue] = React.useState(0);
}
[value, setValue]
– array destructuring in ES 6.
useState
is return two element.
- First element is the value of a state
- Second element is the function to update the state
- Naming convention doesn’t matter, but the order does
** How to swapping element using array destructuring ?
#2 useEffect
useEffect
– a combination of componentDidMount
, componentDidUpdate
and componentWillUnmount
.
@ Example
import React, { useEffect } from 'react';
function Example() {
useEffect(() => {
// synchronous callback
windows.addEventListener();
// cleanup, equivalent to componentWillUnmount
return () => {
windows.removeEventListener();
}
}, [dependencies])
// dependencies will handle whether to re-run the useEffect or not
// if dependencies value remain the same. it will skip useEffect
// otherwise, execute the useEffect
}
@ Example – Execute once
import React, { useEffect } from 'react';
function Example() {
useEffect(() => {
// Equivalent to componentDidMount
// Code, execute once on when the component mounted
}, [])
}
@ Example – Execute every re-render
import React, { useEffect } from 'react';
function Example() {
useEffect(() => {
// Code, execute on every re-render
})
}
@ Example – Execute only when dependencies updated
import React, { useEffect } from 'react';
function Example() {
useEffect(() => {
// Equivalent to componentDidUpdate
// Execute if dependencies updated
// Otherwise, skip useEffect
}, [dependencies])
}
@ Example – Asynchronous in useEffect
import React, { useEffect } from 'react';
function Example() {
// You are not allowed to do this, the callback is always synchronous
useEffect(async () => {
// Code
}, [dependencies])
}
// you can try below
function Example() {
useEffect(() => {
async fetchSomething() {
// Code
}
fetchSomething();
})
}
#3 Yet another example
@ Example – Fetching blog posts
import React, { useState, useEffect } from 'react';
function MyBlog() {
const [posts, setPosts] = useState([]);
const [selectedCategories, setSelectedCategories] = useState(new Set([])); // Selected categories for filter
const [page, setPage] = useState(0); // blogposts pagination
const [loading, setLoading] = false;
useEffect(() => {
// Declare a function to fetch blogpost from WordPress API
async fetchPosts(blogPage, blogCategory) {
try {
setLoading(true);
const res = await fetch(
`https://blog.yikkok.com/wp-json/wp/v2/posts?_embed&page=${blogPage}&categories=${blogCategory}&per_page=5`,
{
method: "GET"
}
).then(response => response.json());
if (res) {
setPosts([...res]);
setIsLoading(false);
}
} catch (error) {
// handling error
setIsLoading(false);
}
}
const selectedCategoriesStr = Array.from(selectedCategories).join(",");
fetchPosts(page, selectedCategoriesStr)
}, [page, selectedCategories])
// Because I'm using page and selectedCategories inside useEffect,
// Thus, I pass the page and selectedCategories as the dependencies,
// As I want the useEffect to re-run whenever either one updated
function handleUpdatePage(pageNumber) {
setPage(pageNumber);
}
function handleUpdateSelectedCategories(selected) {
// A closure
return () => {
// Just for demo purpose, it may contain some bugs...
const cloned = new Set(selectedCategories);
if (cloned.has(selected)) {
cloned.delete(selected)
} else {
cloned.add(selected)
}
setSelectedCategories(cloned);
}
}
return (render UI)
}
#4 Custom React Hooks
Let’s write a custom React Hooks, Using useState
and useEffect
.
import React, { useState, useEffect } from 'react'
// React Hooks naming convention, always prefix with 'use'
export default function useBlogPosts() {
const [posts, setPosts] = useState([]);
const [selectedCategories, setSelectedCategories] = useState([]);
const [page, setPage] = useState(0);
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
useEffect(() => {
async fetchPosts(blogPage, blogCategory) {
try {
setLoading(true);
const res = await fetch(
`https://blog.yikkok.com/wp-json/wp/v2/posts?_embed&page=${blogPage}&categories=${blogCategory}&per_page=5`,
{
method: "GET"
}
).then(response => response.json());
if (res) {
setPosts([...res]);
setLoading(false);
}
} catch (error) {
// handling error
setLoading(false);
setError(error.message);
}
}
const selectedCategoriesStr = Array.from(selectedCategories).join(",");
fetchPosts(page, selectedCategoriesStr)
}, [page, selectedCategories]);
function handleUpdateSelectedCategories(selected) {
const cloned = new Set(selectedCategories);
if (cloned.has(selected)) {
cloned.delete(selected)
} else {
cloned.add(selected)
}
setSelectedCategories(cloned);
}
function handleUpdatePage(pageNumber) {
setPage(pageNumber);
}
return {
posts,
loading,
error,
page,
selectedCategories,
handleUpdateSelectedCategories,
handleUpdatePage
}
}
#5 Use the custom React Hooks
// Refactor MyBlog Component
import React from 'react';
import useBlogPosts from 'src/hooks/useBlogPosts';
function MyBlog() {
const blog = useBlogPosts();
// blog.selectedCategories
// blog.handleUpdatePage
// blog.handleUpdateSelectedCategories
// blog.error
// blog.loading
// blog.posts
// blog.page
}
With custom React Hooks, we can separate the stateful logic out of UI component, which make us easier to debug the code without being distracted by the UI code.
Please visit my github commit, how I refactor the source code into custom React Hooks.
Takeaway
useState
- Access and interact state in functional component
useEffect
- Synchronous
- Work similar to
componentDidMount
,componentDidUpdate
andcomponentWillUnmount
Custom React Hooks – Reuse stateful logic.
Thanks for reading. 😁
Comments
(0 Comments)