in this react example from https://reactjs.org/docs/hooks-custom.html, a custom hook is used in 2 different components to fetch online status of a user...
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;
}
then its used in the 2 functions below:
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>
);
}
my question is, will the function be executed individually everywhere where it is imported into a component? Or is there some thing like sharing the state between components, if it is defined as a separate exported function? e.g I execute the function only once, and the "isOnline" state is the same in all components?
And if its individually fetched, how would I have to do it to fetch data only once globally, and then pass it to different components in my React app?
First, you'll need to create two components, one parent and one child. Next, you'll import the child component in the parent component and return it. Then you'll create a function and a button to trigger that function. Also, you'll create a state using the useState Hook to manage the data.
Do two components using the same Hook share state? No. Custom Hooks are a mechanism to reuse stateful logic (such as setting up a subscription and remembering the current value), but every time you use a custom Hook, all state and effects inside of it are fully isolated.
Put the fetchData function above in the useEffect hook and call it, like so: useEffect(() => { const url = "https://api.adviceslip.com/advice"; const fetchData = async () => { try { const response = await fetch(url); const json = await response. json(); console. log(json); } catch (error) { console.
To share state data across multiple components in a large project, I recommend to use Redux or React Context.
Nevertheless, you can implement a global isOnline state using the Observer pattern (https://en.wikipedia.org/wiki/Observer_pattern):
// file: isOnline.tsx
import { useEffect, useState } from 'react';
// use global variables
let isOnline = false;
let observers: React.Dispatch<React.SetStateAction<boolean>>[] = [];
// changes global isOnline state and updates all observers
export const setIsOnline = (online: boolean) => {
isOnline = online;
observers.forEach(update => update(isOnline));
};
// React Hook
export const useIsOnline = (): [boolean, Function] => {
const [isOnlineState, setIsOnlineState] = useState<Object>(isOnline);
useEffect(() => {
// add setIsOnlineState to observers list
observers.push(setIsOnlineState);
// update isOnlineState with latest global isOnline state
setIsOnlineState(isOnline);
// remove this setIsOnlineState from observers, when component unmounts
return () => {
observers = observers.filter(update => update !== setIsOnlineState);
};
}, []);
// return global isOnline state and setter function
return [isOnlineState, setIsOnline];
}
import { useIsOnline } from './isOnline';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useIsOnline();
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
function FriendStatus(props) {
const isOnline = useIsOnline()[0];
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
function FriendListItem(props) {
const isOnline = useIsOnline()[0];
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}
Edit: Inside useIsOnline
return isOnlineState
created with useState
instead of the isOnline
variable because otherwise React can't pass the changes down to the component.
Edit 2: Make useEffect
independent of isOnlineState
so the hook does not unsubscribe and resubscribe on each variable change.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With