Now that #558 has landed, and as pointed out in #898, it would be very useful to let people create new environments on their own such as:
const environment = new Relay.Environment();
@josephsavona suggested in #558 that this will happen as part of #559 however this meta task seems not so trivial and will likely take some time so why wait when it seems like we can leverage all the hard work people put into making Relay contextual already ?
Thanks for starting the discussion about this. RelayEnvironment is one of a few new APIs that we'd like to export as public API:
Relay.Environment (RelayEnvironment)Relay.Renderer (RelayRenderer)Relay.ReadyStateRenderer (RelayReadyStateRenderer)In particular, using RelayEnvironment also requires using one of the latter new components, so any PR should export these all together.
Ideally, we'd also document these APIs, mark Relay.Store and Relay.RootContainer as deprecated, and update the examples to reference the new APIs instead. I think it's reasonable to start by just exporting the new APIs to unblock anyone who needs them, and then do the deprecation/documentation/examples in a follow-up step.
I'll comment again on the PR just to be clear.
My use case for Relay.Environment is to be able to set a new environment (e.g. when logging out and the back in as another user).
Is it expected that eventually we'll be able to set Relay.Environment = new Environment()?
I'm trying to make such an amend at the moment. It requires that anywhere that uses RelayStore to be updated to use RelayPublic.Environment. I've ran into a problem in that RelayInternals is required by RelayPublic and so can't use RelayPublic.Environment as it's not been set yet.
It'd be great to get your thoughts on it @josephsavona
@lprhodes The intention is that an application would maintain a reference to a single instance of Relay.Environment, and pass that environment to each root container (Relay.Renderer, which replaces RelayRootContainer).
To "reset" on user logout, you would simply create a new environment instance (environment = new Relay.Environment()).
Once @tlvenn's PR lands (with the changes described above), this will be something like:
let environment = new Relay.Environment();
function logout() {
environment = new Relay.Environment();
}
React.render(
<Relay.Renderer environment={environment} ... />,
...
);
Good to hear @josephsavona !
I initially focused solely on the RelayEnvironment because that is the only one which is currently totally out of reach because it is not exported to the lib folder. For reference, the other 2 can be imported as such:
import RelayRenderer from 'react-relay/lib/RelayRenderer';
import RelayReadyStateRenderer from 'react-relay/lib/RelayReadyStateRenderer';
I will add those 2 to the API.
@lprhodes to handle the login/logout scenario and keep the convenience of the RelayStore singleton, you can roll your own version which is a wrapper around RelayEnvironment.
https://gist.github.com/tlvenn/9c468a5b50e0497bd319bfa0ab8b6c7f
@josephsavona Is it safe to actually replace the current environment without any check ? Such as:
invariant(
!this._env.getStoreData().getChangeEmitter().hasActiveListeners() &&
!this._env.getStoreData().getMutationQueue().hasPendingMutations() &&
!this._env.getStoreData().getPendingQueryTracker().hasPendingQueries(),
'RelayStore.reset(): Cannot reset the store while there are active ' +
'Relay Containers or pending mutations/queries.'
);
@tlvenn It's obviously safe to _create_ a new RelayEnvironment instance at any time, since it just creates a new object that is independent of any previous environments that may already exist. Whether you want to add the additional checks is up to you (though certainly safer to check).
I should have chosen my words more carefully, I meant good practice rather than safe. And I guess it really depends on how those environments are ultimately manipulated / used.
For example, in the gist I linked, since the environment is not actually passed down directly but shielded in a singleton, any present renderer would instantly use the new env instead of referencing the old one which may or may not present some issues.
Would anyone know if it's sufficient enough to inject the NEW network layer directly into Relay?
// We create a new environment
currentEnvironment = new Relay.Environment();
// Here we add our networklayer
const networkLayer = new RelayNetworkLayer({ ... middleware here ... })
// Finally we inject the network layer directly into relay (I'm not sure if this is the right way todo it)
Relay.injectNetworkLayer(networkLayer);
If I don't inject it directly into relay I'll get all sorts of mutation errors. The way I was doing it before was inserting currentEnvironment INTO relay the environment={} prop.
@jamesone Relay.injectNetworkLayer is just a helper that injects the layer on the default environment instance. The correct approach would be to inject the network layer on the new environment directly:
const currentEnvironment = new Relay.Environment();
const networkLayer = new RelayNetworkLayer({ ... middleware here ... });
currentEnvironment.injectNetworkLayer(networkLayer);
Most helpful comment
@lprhodes The intention is that an application would maintain a reference to a single instance of
Relay.Environment, and pass thatenvironmentto each root container (Relay.Renderer, which replaces RelayRootContainer).To "reset" on user logout, you would simply create a new environment instance (
environment = new Relay.Environment()).Once @tlvenn's PR lands (with the changes described above), this will be something like: