xaviergonz / mobx-keystone

A MobX powered state management solution based on data trees with first class support for Typescript, support for snapshots, patches and much more
https://mobx-keystone.js.org
MIT License
549 stars 25 forks source link

mk-gql? #184

Closed jeffchuber closed 4 years ago

jeffchuber commented 4 years ago

Hi 👋 and thanks for the easy to use and powerful library!

I'm working on integrating a React-MobxKeystone front-end with my graphql backend and was curious if the community had recommendations about tools and design. Example code is also greatly appreciated!

Here are some theses, which may or may not be way off the mark:

~I'm attempting a port of mst-gql to "mk-gql" - will see how it goes and share if it works. Proving hard to merge the APIs~

dodas commented 4 years ago

I can't really recommend mst-gql's approach. Imo mapping your frontend store 1:1 to GraphQL api does not work well.

I would be interested in an thin wrapper around urql. At least to have data, errors and loading for each query as observable object.

jeffchuber commented 4 years ago

@dodas yea that sounds much better. in retrospect, it does feel like the best-practices have moved away from how mst-gql does things and using mst-gql or an equivalent would be quickly become a dead-end in one's stack.

dodas commented 4 years ago

I am experimenting with this right now so I will keep you updated with my findings.

dodas commented 4 years ago

I found a little interesting util that could help with managing async states in your store: mobx task.

Currently, I just have a urql instance initialized in my root store and I access it in any child store like this:

const { gql } = getRootStore<RootStore>(this)!;

How have you decided to manage your gql queries?

jeffchuber commented 4 years ago

@dodas I've been trying to fully separate views-stores-services. so that each one only has to think about itself.

The general idea is...

  1. View trigger something
  2. That immediately gets detected via patch
  3. Service picks it up and applies the patch serverside. If request fails, it runs the inversePatch

For this pattern, it does raise questions like: for a given view... you can know what data to put on it (eg a list of teams), but how and when do you know to fetch that list of teams vs used cached? I think my preference is: show cached right away always, and then have a loading indicator for the additional items. This mimics the "optimistic UI" pattern as used above. I am currently trying to figure out how to merge the response with the existing local data (for a list of teams for instance). I think applySnapshot is what I want... I do need to make sure that I don't stomp local-only data like team.currentTeam for instance. It would be great to be able to pass an exception list to model serialization so you could define your local-only data. Of course this can be done manually and outside keystone.

Doing this via patches is proving difficult tbh and I don't have it all working yet.

I would say this is the big "missing" piece of keystone for me is how to manage local-server state and reconcile things. There is a todo example which hints at it - but it assumes many things like: node backend, mobx-keystone on backend, all state is synced, etc.

cc @dodas

xaviergonz commented 4 years ago

Why not store local only state in its own root store subtree (or even a whole different root store). For example, the root store could have a "local" property and a "synced" property and then you could only capture / apply patches under the synced subtree