This repository is proof of concept of implementing PubSub architecture in react using react context, swr and wretch.
Sometimes it's needed to revalidate data fetched and displayed by components that were mounted and possibly will be mounted again in the future. For example, user goes to list of some resources, then goes to page where can create new resource, then gets back to list of resources.
What happened here is:
- List of resources (mount some component
List
, mount hooks likeuseGetApi
, fetch data by those hooks) - Go to create page (mount new component
Create
, mount hooks likeuseUpdateApi
, unmountList
anduseGetApi
) - Create resource (use
useUpateApi
) - Go back to list of resources (mount
List
anduseGetApi
again)
The problem is in step 3. where there is no way to notify List
component that data has changed and it should be
revalidated.
In case of using eventEmitter and eventListner it would be:
- Create resource (use
useUpateApi
), and emit eventresourceCreated
- Go back to list of resources (mount
List
anduseGetApi
again), and listen to eventresourceCreated
But in fact List
and useGetApi
were not mounted when event was emitted, so it didn't get notified.
To achieve expected behaviour, we need to store events somewhere and then notify components during their mount phase.
This project shows how to use PubSub pattern and simplified actor's model mailboxes to store events and notify unmounted (that will probably mount again in the future) about need of data revalidation.
Publisher - some hook or component that can notify others about need of data revalidation Subscriber - some hook or component that can be notified about need of data revalidation
- Publisher can emit event only when it's mounted
- Publisher can emit only one event at a time
- Single event can be delivered to multiple subscribers
- Subscribers are ephemeral, they can be mounted and unmounted multiple times
- Subscribers doesn't store it's state
- When subscriber mounts, it should be notified about all events that were emitted when it was unmounted
- When subscriber is mounted, it should react in real time to events emitted by publishers
- When subscriber is unmounted, it should stop reacting to events emitted by publishers
- Application is wrapped by
PubSubProvider
which contains logic of subscription, unsubscription and notification processes
// _app.tsx
const App = ({Component, pageProps}: AppProps) => (
<PubSubProvider>
<SWRConfig>
<Component {...pageProps} />
</SWRConfig>
</PubSubProvider>
);
- Hooks responsible for fetching data subscribes and unsubscribes to events
export const useGetApiData = (url: string) => {
// ... some code to fetch data
// some method to revalidate data
const mutate = () => {
}
const {subscribe, unSubscribe} = usePubSub();
useEffect(() => {
const events: IEvent[] = ["USER_CREATED", "USER_DELETED"];
subscribe({
events: events,
url: url,
callback: () => {
mutate();
},
});
return () => {
unSubscribe({
events: events,
url: url,
callback: () => {
mutate();
},
});
};
}, [mutate, subscribe, unSubscribe, url]);
return {data, isLoading, error};
};
- Hooks or component responsible for data updated emits event
export const RefreshButtons = () => {
const {dispatch} = usePubSub();
return (
<div>
<button
onClick={() => {
dispatch("USER_CREATED");
}}
>
emit event
</button>
</div>
);
};
Take a look at comments in PubSubProvider.tsx
pnpm install
pnpm run dev
To see exact behaviour, open network tab in dev tools and see observe requests to /api/dummy