Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[meta] Make all state contextual #558

Closed
13 of 15 tasks
josephsavona opened this issue Nov 7, 2015 · 19 comments
Closed
13 of 15 tasks

[meta] Make all state contextual #558

josephsavona opened this issue Nov 7, 2015 · 19 comments
Assignees

Comments

@josephsavona
Copy link
Contributor

This is a meta-task to track progress toward making all Relay state contextual, such that multiple instances of Relay can be run in the same JS context. The primary motivation is to support server rendering in open source, where sharing JS contexts is the norm.

Tasks:

  • GraphQLQueryRunner
  • GraphQLPendingQueryTracker should write query results into the contextual RelayStoreData instance
  • GraphQLDeferredQueryTracker: should read query root IDs from the contextual RelayStoreData instance
  • RelayMutationTransaction should write mutation results into the contextual RelayStoreData instance
  • GraphQLStoreRangeUtils - this holds a global mapping of dataID -> range information, and will have to be made contextual. The primary caller is readRelayQueryData.
  • GraphQLStoreChangeEmitter notifies components (or other observers) of data when it changes.
  • Create RelayEnvironment
  • Make RelayStore a singleton instance of RelayEnvironment
  • Change RelayContainer/RelayRenderer to access data via the React context
  • Contextualize RelayRenderer
  • Make Relay.injectTaskScheduler a method on RelayEnvironment
  • Contextualize the network layer and Relay.injectNetworkLayer
  • Contextualize Relay mutations (cannot create props until the store to which it will be applied is known) (Contextualize Relay mutations #699)

Note: the following will be completed as part of #559:

  • Document RelayEnvironment, make it accessible via Relay.Environment or other, and remove any unsupported APIs (or mark them as such).
  • Promote RelayRenderer to public API
@josephsavona
Copy link
Contributor Author

cc @devknoll who's started experimenting with this in #557

@devknoll
Copy link
Contributor

devknoll commented Nov 8, 2015

Optionally, Relay.injectTaskScheduler and Relay.injectNetworkLayer could be moved to the Relay Context class to allow different schedulers/network layers per context.

I think this is actually fairly critical for server side rendering.

@devknoll
Copy link
Contributor

devknoll commented Nov 8, 2015

@josephsavona Do we want RelayStore to own the RelayStoreData instances? Seems like yes, but wanted to confirm.

@devknoll
Copy link
Contributor

devknoll commented Nov 8, 2015

@josephsavona Also GraphQLStoreRangeUtils seems a little tough. Not sure who should own the instance in this case. Going to try keeping it in RelayStoreData and passing it down.

@josephsavona
Copy link
Contributor Author

The methods for injecting these should be on Relay.Store since that's public, but they should save the scheduler/network layer to RelayStoreData.

@josephsavona
Copy link
Contributor Author

Re RangeUtils, agree this map can be saved into StoreData.

@devknoll
Copy link
Contributor

devknoll commented Nov 8, 2015

Looks like GraphQLStoreChangeEmitter depends on GraphQLStoreRangeUtils too. How should we approach that?

@josephsavona
Copy link
Contributor Author

I was on my phone earlier, so here's more context on each of the above

GraphQLStoreChangeEmitter also needs to be contextualized. It doesn't need to depend on GraphQLStoreRangeUtils - instead, RelayStoreData could be changed to call changeEmitter.broadcastChangeForID with an ID that is already in canonical form. RelayStoreData will own the range utils so this should be okay.

Re the distinction between RelayStore and RelayStoreData - in the interim, it's probably best to put all public methods on RelayStore, while holding and modifying all state in RelayStoreData.

@devknoll
Copy link
Contributor

devknoll commented Nov 8, 2015

Super helpful, thanks 👍

ghost pushed a commit that referenced this issue Nov 12, 2015
Summary: Contextualize `RelayMutationTransaction` and update call sites.

Original Summary:

Builds on #561. Part of #558
Closes #562

Reviewed By: yungsters

Differential Revision: D2632150

fb-gh-sync-id: 5e40ce6d3a3dea5bd10f131aec43d1950877c62b
ghost pushed a commit that referenced this issue Nov 12, 2015
Summary: Converts `ChangeEmitter` to a class instead of singleton and holds an instance in `RelayStoreData`. Note that `QueryResolver` was already contextualized (it accepts an instance of `RelayRecordStore`) but it now needs the `RelayStoreData` instance to get access to the change emitter.

Original:Builds on #562. Part of #558
Closes #565

Reviewed By: yungsters

Differential Revision: D2632148

fb-gh-sync-id: b5073151d6459c018bc56654a9deb8bb407fcc41
@vslinko
Copy link
Contributor

vslinko commented Jan 10, 2016

@josephsavona you can use this syntax to track subtasks:

* [ ] In progress
* [x] Done

Result:

  • In progress
  • Done

ghost pushed a commit that referenced this issue Jan 20, 2016
Summary:
> This PR is another step toward making all Relay state contextual (#558). Originally this was submitted as a part of #683, but josephsavona [suggested](#683 (comment)) to split it to smaller PRs.

`RelayContext` will ultimately be the public API of Relay Core, exposing all methods required to implement declarative APIs such as `RelayRootContainer` and `RelayContainer`, and will manage its own private instance of `RelayStoreData` (which will be an implementation detail). This diff is a first step in that direction:
- Creates the `RelayContext` class
- Changes `RelayStore` to be a (singleton) instance of the above, using the singleton `RelayStoreData` to ensure that callers of `RelayStoreData.getDefaultInstance()` get access to the same information as that accessed by via `RelayStore` - i.e., that all existing apps keep working as-is.

Closes #698

Reviewed By: yungsters

Differential Revision: D2784307

fb-gh-sync-id: e1764f9e0ef1dc7a1d1016fe8fdfd9012e7e63d3
ghost pushed a commit that referenced this issue Feb 6, 2016
Summary:
This PR is another step toward making all Relay state contextual (#558). Originally this was submitted as a part of #683, but josephsavona [suggested](#683 (comment)) to split it to smaller PRs.
Closes #761

Reviewed By: wincent

Differential Revision: D2863416

fb-gh-sync-id: f9907959aac71b14e54d2746b86927b6fd8b1952
@leebenson
Copy link

is there a timeline for release? I'd love to contribute, but finding the time to get up to speed with the internals would probably be longer than it'd take you to finish.

@josephsavona
Copy link
Contributor Author

Just a heads up that this and the react-relay/Relay core split will be my main area of focus for the next couple months. Contributions are welcome, but definitely reach out to us before starting a major PR in this area.

@josephsavona
Copy link
Contributor Author

@leebensen there are always things that need attention. I'd recommend starting with a small task at first - take a look at issues tagged with "good first bug"!

ghost pushed a commit that referenced this issue Mar 7, 2016
Summary:== Original Description ==
This PR is another step toward making all Relay state contextual (#558).

Contextual `RelayNetworkLayer` is important for server-side rendering. It will allow to inject a contextual network layer initialized with client request specific params (e.g. authentication cookies) on the server. Currently it is impossible because the injected network layer is global, and shared between client requests.

== Summary of Changes ==
- Moves `fetchRelayQuery` to a method on `RelayNetworkLayer`, which is now a class with an instance held by each `RelayStoreData`, thereby making the network layer contextual to the context instance.
- Changes `Relay.injectNetworkLayer` to a facade for `RelayStore.injectNetworkLayer()`.
- Changes the FB/OSS `Relay` module to inject a network layer directly on `RelayStore`.
- Re-create `fetchRelayQuery` in relay-fb for convenience

Closes #704

Reviewed By: wincent

Differential Revision: D3016293

Pulled By: josephsavona

fb-gh-sync-id: 2e5f3163bc048a089776477b3d2dac2546fd9f48
shipit-source-id: 2e5f3163bc048a089776477b3d2dac2546fd9f48
ghost pushed a commit that referenced this issue Mar 7, 2016
Summary:== Original Description ==
This PR is another step toward making all Relay state contextual (#558). Originally this was submitted as a part of #683, but josephsavona [suggested](#683 (comment)) to split it to smaller PRs.

== Summary of Changes ==
- Make `relayContext` a required prop on `RelayRenderer`
- Change `RelayRootContainer` to pass `RelayStore` (a default instance of RelayContext) as the relayContext prop to its internal RelayRenderer
- Update tests (in particular, checking that changing the relayContext prop on RelayRenderer works as expected)
- Update products that use RelayRenderer directly to pass RelayStore as the Relay context

Closes #810

Reviewed By: wincent

Differential Revision: D3006237

Pulled By: josephsavona

fb-gh-sync-id: 6cf774f1ee5a81ec9d3c5e499f0d1e25fe3befc5
shipit-source-id: 6cf774f1ee5a81ec9d3c5e499f0d1e25fe3befc5
josephsavona referenced this issue Mar 7, 2016
Reviewed By: wincent

Differential Revision: D3017230

fb-gh-sync-id: 0de370b24e0db51b3dbbce4a55f6eb8167390773
shipit-source-id: 0de370b24e0db51b3dbbce4a55f6eb8167390773
@josephsavona josephsavona self-assigned this Mar 7, 2016
@josephsavona
Copy link
Contributor Author

Heads up that we're renaming RelayContext to RelayEnvironment. It's common in Relay apps to render multiple RelayRootContainers (e.g. one for each tab in a TabView), and RelayContext suggests an incorrect association with React contexts which are one-per-root component.

ghost pushed a commit that referenced this issue Mar 8, 2016
Summary:== Original Description ==
This PR is another step toward making all Relay state contextual (#558). Originally this was submitted as a part of #683, but josephsavona [suggested](#683 (comment)) to split it to smaller PRs.

Currently, Relay resolve mutations props using the global `RelayStore`, and store them in the `props` instance field of `RelayMutation`. That makes it impossible to contextualize Relay mutations without changing the public API.

After analyzing different alternatives, I have found that the probably cleanest solution is not to store resolved mutation props in an instance field, but to pass them as an argument to each of the mutation methods. That way mutations can be reused in different `RelayStoreData` contexts, and also they can be reused in the same context but at different times, because props are re-resolved at each mutation execution.

== Summary of Changes ==
- Change `RelayMutation` constructor to not immediately resolve data for fragment props
- Add `bindContext` method on RelayMutation, called when the mutation is committed on a specific RelayContext
- This necessitated adding the `read` method to `RelayContextInterface`, and stubbing this method on alternative context implementations.
- Updated mutation docs to mention this method.

Closes #699

Reviewed By: yungsters

Differential Revision: D2913334

Pulled By: josephsavona

fb-gh-sync-id: 5051fddf068fc8bc7379bb55c8b1e4d97e33313c
shipit-source-id: 5051fddf068fc8bc7379bb55c8b1e4d97e33313c
@josephsavona
Copy link
Contributor Author

As of 8e53183, all of Relay's internal state tracking has been contextualized. Each instance of RelayEnvironment is an isolated environment with its own cache of data, network layer, task scheduler, etc. This is an important prerequisite for server rendering in open source as well as allowing some new use cases. The next step is #559 - splitting Relay Core and the React/Relay integration layer - follow along there for more details.

Thanks especially to @denvned and @devknoll for their impressive contributions!

@schickling
Copy link
Contributor

Awesome. Looking forward to it! 🎉

@rodrigopr
Copy link

Amazing work! Thanks @denvned, @devknoll, @josephsavona . 🎉

@KyleAMathews
Copy link
Contributor

Yeah!

On Wed, Mar 9, 2016 at 6:59 AM Rodrigo Ribeiro notifications@github.com
wrote:

Amazing work! Thanks @denvned https://github.com/denvned, @devknoll
https://github.com/devknoll, @josephsavona
https://github.com/josephsavona . [image: 🎉]


Reply to this email directly or view it on GitHub
#558 (comment).

@koistya
Copy link

koistya commented Mar 12, 2016

Great news. Big thanks to all the contributors!

img

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants