Reputation: 3548
I'm after a bit of patterns guidance. I am writing a React front end (using NextJS) to a back end (based on FeathersJS) that relies on a singleton client object. The client will be needed in many different components up and down the tree, basically to make requests to the server for various things.
In the simple examples online, this client
object is managed as a shared global, imported wherever it is needed.
// client.js
import io from 'socket.io-client';
import feathers from '@feathersjs/client';
const socket = io();
const client = feathers();
client.configure(feathers.socketio(socket));
client.configure(feathers.authentication());
export default client;
// consumer somewhere
import client from './client';
client.doStuff()
The problem with this is that the global initialisation interacts badly with webpack and server-side rendering, and in general doing initialisation like this in the global scope feels wrong.
Where would you best put this so that (a) it's initialised early but only on client-side; (b) it's easy to get hold of and use from components up and down the component tree?
One option would obviously be just to manage a global singleton that's initialised on demand when first used:
let client = null;
function getClient() {
global client;
if(client === null) {
// initialise client
}
return client;
}
But I'm wondering if there's a more canonical way in React, e.g. using context?
Upvotes: 2
Views: 3393
Reputation: 38173
The client will be needed in many different components up and down the tree ... But I'm wondering if there's a more canonical way in React, e.g. using context?
I think React Context is good for these sorts of singleton objects, especially if the object will be used in many spots up and down the three. There are many, many examples of this in practice. I would consider myself a judicious user of context, and I would say this is what the Context API was designed for. For example, take useApolloClient
. It consumes an Apollo Client that was previously put into context by an ApolloProvider
so that it can be used anywhere in the tree.
The problem with this is that the global initialisation interacts badly with webpack and server-side rendering ... Where would you best put this so that (a) it's initialised early but only on client-side; (b) it's easy to get hold of and use from components up and down the component tree?
Yes, initializing these objects in the render tree on the server side can be tricky or bad. If you're using something like Next.js , it makes sense to initialize these objects "above" the render tree, either at a top-level module scope or in getInitialProps
.
Upvotes: 1