So, it's been a while since the hooks came in and I've been trying to find time to try and learn to create custom hooks. Really mind-boggling ๐ง . Though the interesting part is that the concept may be simple but if you find the right use case to it.
The first thing i wanted to try out was to make network request and to see how we can implement using hooks. The usual way in react was obviously setState. Assuming that most of you have worked with setState. Now let's see how to write it in a functional component using Hooks.
For this let's use JSON placeholder to fetch posts.
import React,{ useState } from "react";
// URL to fetch posts
const postsUrl = "https://jsonplaceholder.typicode.com/posts"
// Our Component
const ListPosts = () => {
// Using state hook to set if loading
const [ loading, setLoading ] = useState(true);
// Fetch and set list of posts
const [ posts, setPosts ] = useState([]);
//Here we fetch the posts and add it to posts state
fetch(postsUrl)
.then(res => res.json())
.then(data => { setPosts(data); setLoading(false); })
.catch(err => {
alert('Error fetching posts');
setLoading(false);
});
//Our Component which will lists posts
return(
<div>
// Loop through the list of posts
<h1>My Posts <span>{posts.length}</span></h1>
{loading ?
<h1>Loading posts...</h2>
: posts.map(post => (
<div>
<h3>{post.title}</h3>
<hr/>
<p>{post.body}</p>
</div>
})}
</div>
)
}
In this component we used useState hook to set posts and loading state. But now let's see how we can rewrite this as a hook separating the logic from component.
First let's use the effect hook which will react to changes inside the component. Let's check it out.
React.useEffect(() => {
// Function called whenever something updates in component
},[ /* Update based on variable */ ])
Now let's see how to use it in our component
import React,{ useState } from "react";
// URL to fetch posts
const postsUrl = "https://jsonplaceholder.typicode.com/posts"
// Our Component
const ListPosts = () => {
// Using state hook to set if loading
const [ loading, setLoading ] = useState(true);
// Fetch and set list of posts
const [ posts, setPosts ] = useState([]);
// Use effect to update component
React.useEffect(() => {
//Here we fetch the posts and add it to posts state
fetch(postsUrl)
.then(res => res.json())
.then(data => { setPosts(data); setLoading(false); })
.catch(err => {
alert('Error fetching posts');
setLoading(false);
});
},[ postsUrl ])
//Our Component which will lists posts
return(
<div>
// Loop through the list of posts
<h1>My Posts <span>{posts.length}</span></h1>
{loading ?
<h1>Loading posts...</h2>
: posts.map(post => (
<div>
<h3>{post.title}</h3>
<hr/>
<p>{post.body}</p>
</div>
})}
</div>
)
}
Now let's separate the logic from the application
// Here is our hook which makes request and returns the posts
const usePosts = (postUrl) => {
const [ loading, setLoading ] = useState(true);
const [ posts, setPosts ] = useState([]);
React.useEffect(() => {
//Here we fetch the posts and add it to posts state
fetch(postsUrl)
.then(res => res.json())
.then(data => { setPosts(data); setLoading(false); })
.catch(err => {
alert('Error fetching posts');
setLoading(false);
});
},[ postsUrl ])
return { loading, posts }
}
// Adding it to our component
const postsUrl = "https://jsonplaceholder.typicode.com/posts";
const ListPosts = () => {
const { loading, posts } = usePosts(postsUrl);
return(
<div> // Loop through the list of posts
<h1>My Posts <span>{posts.length}</span></h1>
{loading ?
<h1>Loading posts...</h2>
: posts.map(post => (
<div>
<h3>{post.title}</h3>
<hr/>
<p>{post.body}</p>
</div>
})}
</div>)
}
So there we go, we have created our first simple custom hook. This is okay if we are going to use static requests to fetch data. What if we are going to recieve a stream of data based on events.
Let's see how we can write the same component using a socket to fetch temperature from an IoT Device. Which will constantly send data.
For this I've created a sample code that streams a random temperature between 0 and 100 using express and socket-io. The code is as below.
// server.js
const app = require('express')();
const server = require('http').createServer(app);
const socket = require('socket.io');
const io = socket(server);
const port = 8080 || process.env.PORT;
io.on('connection', () => {
console.info('SOME ONE IS HERE');
});
setInterval(() => {
const temp = Math.floor(Math.random()* 100);
const topic = 'temperature';
console.info(`TEMP : ${temp}`);
io.emit(topic,temp);
}, 3000);
const listenCb = () => console.table([['status', 'port'],['started',port]])
server.listen(port, listenCb);
Install the dependencies and run the server using the follwoing code
npm i -S socket.io express
# Run the app using nodejs
node app.js
This will constantly send the data every 3 seconds.
Now let's see how to use this in our React's component using custom hooks. First let's write our hook.
import React from 'react';
import PropTypes from 'prop-types';
import socket from 'socket.io-client';
// Use socket to fetch request to data
// Socket server's url and topic in which data is sent
const useSocket = (serverUrl, topic) => {
const [temp, setTemp] = React.useState(0);
const [isConnected, setConnected] = React.useState(false);
React.useEffect(() => {
const client = socket.connect(serverUrl);
client.on("connect", () => setConnected(true));
client.on("disconnect", () => setConnected(false));
client.on(topic, (data) => {
setTemp(data);
})
}, [serverUrl, topic, isConnected]);
return { temp, isConnected };
}
// Our component which sends the request through the topic
const Sockt = () => {
const serverUrl='http://localhost:8080', topic='temperature';
const { temp, isConnected } = useSocket(serverUrl, topic);
return (
<div>
<h4>Temperature</h4>
<h1>{temp}</h1>
<h3>{`CONNECTED: ${isConnected}`}</h3>
</div>
)
}
The component now will show the temperature which is received from the socket server. Every time data is sent through the socket.
I hope, you got to learn something new and interesting. Find the code sandbox for the implementation of what we went through this entire article.
Backend - Socket Server ๐งฆ
https://codesandbox.io/s/express-socket-io-70t5x
React using hooks
https://codesandbox.io/s/priceless-greider-3b814
Top comments (0)