React Hooks II
INFO 253A: Frontend Web Architecture
Kay Ashaolu
Rules of Hooks
- Must use hooks in functional React components
- Must use hooks at the top level of your components, or in your custom hooks
- This means don't use hooks inside conditionals either
- This is because React relies on the order of hooks to determine functionality
- If the order of hooks executed changes dynamically during execution, very hard to figure out bugs will appear
Custom Hooks
- React provides the ability to write your own hooks
- Custom Hooks provide another way to share stateful logic across components
- What is this stateful logic you speak of? Or what does that even mean?
Custom Hooks
- As your front end application becomes more complex, it becomes harder to manage all of the state variables as well as all of the logic that modifies those state variables
- What happens when you want to have some state that affects multiple components?
- React has provided a few ways of accomplishing this task, but typically involve creating more components that contain the shared state at a higher level.
- Hooks provide an alternative path that does not necessiate these "higher order components"
Setup Code
import React, { useState, useEffect } from 'react';
function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
Custom Hooks Example
- We have a component called FriendStatus that displays "Online" if the Friend was online and "Offline" if not
- Note the use of the useEffect hook to define what should happen when the component is created or is updated, and what should happen when it unsubscribes.
Custom Hooks Example
- However imagine if we had another component, a contact list, where we wanted to highlight a person's name if they were online.
- We would write out the logic, but it would require repeating a lot of the same code
Setup code 2
import React, { useState, useEffect } from 'react';
function FriendListItem(props) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}
Refactoring?
- In previous classes I've shown the benefits of putting common code into functions and using that function instead
- Benefits include
- not repeating code which can be error prone
- once you update behavior for the shared function it is available everywhere
- code is easier to read
Let's look at a custom hook
import { useState, useEffect } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
What's happening here?
- The amazing thing is that a custom hook is also just another function: inputs, outputs, and logic
- You can use other hooks inside custom hooks
- You are writing stateful logic that can be shared across components
- You can also fully control the inputs and outputs of your hook. In this case, we pass in a friend ID and return whether that friend is online
How to use custom hook
function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
function FriendListItem(props) {
const isOnline = useFriendStatus(props.friend.id);
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}
That was elegant
- Wasn't it? Those two components are now using the useFriendStatus custom hook, and thus reduced a lot of repeated code.
- If anything were to change with the API or the handling of the API results, we could simply update the useFriendStatus hook and all components using it would be updated
Demo
React Hooks II - Frontend Webarch
By kayashaolu
React Hooks II - Frontend Webarch
Course Website: https://www.ischool.berkeley.edu/courses/info/253a
- 567