Apollo + Meteor: which features exactly are coming in 1.5?

Hmm, perhaps I have to dig deeper into Apollo. We’re using minimongo as a client-side cache only - basically the equivalent of a redux state object, but in this case, the “object” is the minimongo db. By reactive, I only meant that our react components update when we make changes to the local cache (which is what happens if you wire up redux and make changes to the redux state object). So, no Meteor subscriptions, etc - we load data via regular HTTP calls to an api, and insert that data into minimongo. We’re slowly transitioning from meteor subscriptions -> rest api -> apollo (?).

Sure, Apollo takes advantage of a very particular cache format that lets it handle GraphQL queries correctly - you could definitely store that cache format inside Minimongo just because, but I don’t think that would help you since if you queried that Minimongo collection directly you would get some weird stuff. In Apollo you query the cache with GraphQL.

Oh wow! A big lightbulb just went on in my head. I was thinking that Apollo’s GraphQL was just for querying the server. Now everything makes a lot more sense.

I guess that’s what comes from reading random forum posts instead of actually reading the Apollo docs.

5 Likes

The way I thought about it, it would be reworded to: You query GraphQL cache with Apollo Client query fetching API.

A graph in your Medium article:

The cache we are speaking of is the Normalized object store? The Query fetching is something, if using Blaze, we’d find inside a helper (in theory) and what we’d use to query the object store? What is the Refetching part, is this Reactivity? If it is the Reactivity part, is this applied selectively to a query or field?

And what would the blaze-apollo abstraction do for us on top of the Apollo Client? Would it somehow integrate Tracker into the mix?

Ok wow yes, like @babrahams I did not understand this delightful bit. Gotta dig in a bit I suppose - sounds great! Looking forward to messing around with it in 1.5.

Very little! The whole idea is Apollo Client does basically everything, and the Blaze integration does just enough that putting the data into Blaze feels natural. For example:

  1. The React integration is a higher-order component that passes data via props
  2. The Angular 2 integration is a wrapper that gives you an RxJS observable, that Angular handles natively
  3. The Blaze integration is… probably something that lets you do a query in a helper, and integrates with Tracker to make the template re-render at the right time.

That diagram is pretty vague, but let me try to explain:

  1. You call watchQuery, it gives you an observable that initially returns nothing (This is like the initial find in Meteor that returns nothing while the data is loading)
  2. Apollo calls the server with the query you passed, and puts the data in the cache/store (this is similar to the Meteor subscription)
  3. The cache/store updates, the query runs against the cache, which gets the data that was just put into the cache (this is similar to the Meteor Minimongo query)
  4. You get a new result in the observable (this could trigger a Tracker re-run in the Blaze integration)

You can mess around with it now as well! Especially if you are using React or Angular 2 in your app, since those integrations are pretty nice.

4 Likes

@sashko Just to add some more feedback since it might be helpful, when I first looked at Apollo-Client several months ago I also thought it was just a query wrapper with a cache that it used itself… It wasn’t until trying it out and having issues with stale data (cached) and inquiring about forceFetch did I realize you were supposed to query to get the cache and only force fetch when needed.

Perhaps the docs could use something more prominent to state the value prop? I also haven’t read them recently so maybe they’ve also changed a lot since then. (though I need to re-read with the new API changes!).

1 Like

We’re redoing basically 100% of the docs right now, I better hope the new ones make it clear what the thing does :]

4 Likes

I used to use Redux heavily (and still do in a large app) but now with Apollo Client and the container pattern, using Redux or MobX for a global state is really overkill. Typically I just store a handful of keys for modals, alert banner content, viewer token/id, etc…

Previously (a year ago) it was a really hard to pass down props through many layers so Redux was attractive for that… but with the spread operator you can pass down props with {...this.props} into the child and it becomes much more maintainable (and the child should declare prop types of course to keep maintainability).

Redux was also helpful to take async logic out of the view… but Apollo takes 90% of that away and local operations can go into a parent “data container” to retain that same separation of the view (instead of redux action creators).

Lastly I was going to use Redux for some global state… which works fine, but if you don’t have a complex setup you can use context to provide the same thing… a topmost component that holds global state for all of the UI (note i haven’t used this in prod… yet):

const App = React.createClass({
  getInitialState: () => ({}),

  getChildContext: () => ({
    globalState: this.state
  }),

  childContextTypes: {
    globalState: React.PropTypes.object.isRequired
  },

  componentDidMount() {
    // use this to set global state if you really have to, otherwise use context
    window.setGlobalState = (obj) => {
       this.setState(obj);
    }
  },

  render() {
    return this.props.children
  }
})

ReactDOM.render((
  <App>
      { require("./routes").default } // bring in react-router routes
  </App>
), document.getElementById("react-root"));


// some child container in another file:

const Container = React.createClass({
  contextTypes: {
    globalState: React.PropTypes.object.isRequired
  },

  render(props=this.props) {
    return (
      <Home 
        someGlobalCounter={this.context.globalState.counter}
      />
    );
  }
});

Note that you could make your own higher order component so that it works much like connect in redux… perhaps like connectGlobalState(Post) and then globalState and setGlobalState would be available via props.

2 Likes

@SkinnyGeek1010 are you concerned at all that React says using context heavily and for state is an anti-pattern? https://facebook.github.io/react/docs/context.html#when-not-to-use-context

It was also pointed out by mr abramov recently on twitter that using spread operator on props is most-likely an anti-pattern.

I feel like this is the kind of thing we shouldn’t do - quote one tweet from someone talking offhand about what their preferences might be.

2 Likes

@sashko it’s not just someone – it’s from the creator of redux, who is also a core react dev. also, just seeing an example component with spread op:

<Test {...this.props} />

vs props explicity passed in:

<Test a={a} b={b} />

which example looks ‘correct’, easier to test, and debug?

just some food for thought. i guess dev’s can develop things however they want, just want to make sure example code & best practices for something new for a thing like apollo, new devs aren’t pointed in a new ‘best practice’ for apollo from a simple informal forum thread such as this one, which can in turn lead to a lot of code being tossed out in the future, just because it seems like the easiest way to set something up.

3 Likes

You bring up a great point. You really shouldn’t use context except for special use cases. Typically it’s reserved for libraries like redux, mobx, apollo, etc… or anything that has a <Provider>. In this case I was essentially making my own micro library to hold a little bit of global state. As stated this was just for a few things that can’t easily be passed down, like a dropdown modal banner. You don’t want to pass that down 20-30 times down through each component. Every component would have to have knowledge of this modal prop for it to work which is not ideal.

Also worth repeating I haven’t tried this in prod. so there may be significant flaws in it (currently using Redux for that same global state).

I also agree that in general the spread operator is an anti pattern. Ideally you should clearly mark every component with a prop instead of {...this.props} but it comes with a cost. If it stops me from decomposing my component into smaller chunks i’ll pass down with the spread. Also typically i’m only using this in an “area” of the UI like say a comment, and then the comment might have 8 smaller components and in this area I may use it. I would never use the spread from say the root chat page, down through lots of components where it’s very difficult to tell where it’s coming from.

My general rule is to try and pass it down explicitly but if there is a lot sometimes I will pass it down several layers with ...this.props and also typically will omit un-needed ones. Then, most importantly the child view or container container needs to specify propTypes so that if something above changes you’re notified in dev when it breaks. It also has a cost of not being explicit (I think that’s the main rub).

1 Like

Well spread operator works if you consider higher order components where you have no clue what is being passed to the wrapped component. You are just making some changes to behavior but passing the data as it is or slightly modified.

Let say a component may take more than 5 props and the form have 10+ such components why would I write every prop by hand instead of spread operator?

3 Likes

Defining things as anti-pattern is all fine and dandy but there are specific cases where spread operator is a better suited. Similar things have been said in Java community or .NET community regarding ServiceLocator pattern but it is used heavily by many frameworks and there is a use for it.

1 Like

This has gone severely off topic - I’ve also contributed. Let’s go back to the original discussion, and if we want to keep talking about spread operators we can start a new thread.

1 Like

is there (or is there going to be) a repo supplied by MDG that shows what an example app would like like with meteor 1.5 with a full apollo/redux implementation? i think that would help visualize a lot of how to setup things.

off from apollo, it might just help to have a bulleted list of all that is in 1.5. i’m still not quite sure what is coming besides a faster build process :slight_smile:

I was having a conversation with a coworker and trying to explain advantages of Apollo and give some examples, and how it simplifies and lessens the need for redux, but I was having hard time thinking of good, concrete examples. Could you share any sample code of this point above? Or just describe any common examples? Particularly I’m trying to come up with good examples that use Apollo for local operations and state.

This is very helpful, as other stuff you’ve posted, thanks. It would be great to have two versions of an app (like a todo or something) to compare traditional REST+Redux vs Apollo.

1 Like

I have a screencast coming up migrating this older Meteor React app: https://github.com/AdamBrodzinski/react-ive-meteor , though it doesn’t have Redux, it’ll be using the container pattern to separate data handling.

4 Likes

Yeah so while the Blaze discussion is obviously important, I’m still really interested in what we can expect with regards to React + Meteor + Apollo integration in 1.5, as that’s probably where a large number of users are going to attack this from.

What are we likely to see to make integration with Meteor easier? Anything? Because currently I feel like while the data-loading is beautiful and easy… Mutations, Optimistic UI, subscriptions, etc are all way, way, waaaaay harder to do than in Meteor with minimongo, etc.

4 Likes