sonaye / Mobx Apollo
Licence: mit
A MobX and Apollo Client integration utility.
Stars: ✭ 152
Programming Languages
javascript
184084 projects - #8 most used programming language
Labels
Projects that are alternatives of or similar to Mobx Apollo
React Mobx State Tree
Create React App with MobX State Tree, Styled Components and GraphQL
Stars: ✭ 127 (-16.45%)
Mutual labels: apollo-client, mobx
Outline
The fastest wiki and knowledge base for growing teams. Beautiful, feature rich, and markdown compatible.
Stars: ✭ 13,833 (+9000.66%)
Mutual labels: mobx
Nextjs Hasura Boilerplate
🎨 Boilerplate for building applications using Hasura and Next.js
Stars: ✭ 126 (-17.11%)
Mutual labels: apollo-client
React Atom
A simple way manage state in React, inspired by Clojure(Script) and reagent.cljs
Stars: ✭ 133 (-12.5%)
Mutual labels: mobx
Eshoponcontainersddd
Fork of dotnet-architecture/eShopOnContainers in full DDD/CQRS design using my own patterns
Stars: ✭ 126 (-17.11%)
Mutual labels: mobx
Xsm
State Management made eXtraordinarily simple and effective for Angular, React, and Vue
Stars: ✭ 138 (-9.21%)
Mutual labels: mobx
Apollo Link Logger
A logger for Apollo Link that resembles redux-logger
Stars: ✭ 148 (-2.63%)
Mutual labels: apollo-client
React Redux Graphql Apollo Bootstrap Webpack Starter
react js + redux + graphQL + Apollo + react router + hot reload + devTools + bootstrap + webpack starter
Stars: ✭ 127 (-16.45%)
Mutual labels: apollo-client
Awesome Apollo Graphql
A curated list of amazingly awesome things regarding Apollo GraphQL ecosystem 🌟
Stars: ✭ 126 (-17.11%)
Mutual labels: apollo-client
Rnn Starter
🤹 Production-ready starter for your next React Native App! Powered by cli-rn, React Native Navigation, Expo, Reanimated 2, Notifications, Over-The-Air Updates, Mobx, Dark Mode, and Localization.
Stars: ✭ 127 (-16.45%)
Mutual labels: mobx
Graphql Directive
Use custom directives in your GraphQL schema and queries 🎩
Stars: ✭ 142 (-6.58%)
Mutual labels: apollo-client
Lit Mobx
Mixin and base class for using mobx with lit-element
Stars: ✭ 126 (-17.11%)
Mutual labels: mobx
Fullstack Apollo React Boilerplate
💥A sophisticated Apollo in React boilerplate project.
Stars: ✭ 136 (-10.53%)
Mutual labels: apollo-client
Reactql
Universal React+GraphQL starter kit: React 16, Apollo 2, MobX, Emotion, Webpack 4, GraphQL Code Generator, React Router 4, PostCSS, SSR
Stars: ✭ 1,833 (+1105.92%)
Mutual labels: apollo-client
Typescript Expo Apollo Boilerplate
Clean boilerplate for TypeScript + Expo (React Native) + React Apollo (GraphQL)
Stars: ✭ 144 (-5.26%)
Mutual labels: apollo-client
mobx-apollo
Installation
yarn add mobx mobx-apollo
Usage
import graphql from 'mobx-apollo';
type config = {
client: apolloClientInstance, // new ApolloClient()
query: gqlInstance, // gql`..`
onError?: Function,
onFetch?: Function, // invoked every time new data is fetched
...ApolloWatchQueryOptions // (see Apollo Client docs)
};
const store = new class {
constructor() {
this.allPosts = graphql({ ...config });
// or lazy load it
extendObservable(this, {
get allPosts() {
return graphql({ ...config });
}
});
// when lazy loading, you should return graphql() without adding anything extra within the block to avoid over-fetching
// utilize another computed for any extra checking or manipulation of data
}
}();
autorun(() => console.log(toJS(store.allPosts.data.allPosts))); // [{ title: 'Hello World!' }]
type response = {
error: ApolloError, // (see Apollo Client docs)
loading: boolean,
data: { queryAlias: Array<Object> },
ref: ApolloObservableQuery // (see Apollo Client docs)
};
Examples
Example without subscriptions
import React, { Component } from 'react';
// create-react-app example
// yarn add apollo-client-preset graphql graphql-tag mobx mobx-apollo mobx-react
import gql from 'graphql-tag';
import graphql from 'mobx-apollo';
import { ApolloClient, HttpLink, InMemoryCache } from 'apollo-client-preset';
import { extendObservable } from 'mobx';
import { inject, observer, Provider } from 'mobx-react';
// schema built with Graphcool
// type Post implements Node {
// id: ID! @isUnique
// title: String!
// createdAt: DateTime!
// updatedAt: DateTime!
// }
// fragments, queries and mutations
const postFragment = gql`
fragment post on Post {
id
title
createdAt
updatedAt
}
`;
const allPostsQuery = gql`
{
allPosts {
...post
}
}
${postFragment}
`;
const createPostMutation = gql`
mutation createPost($title: String!) {
createPost(title: $title) {
...post
}
}
${postFragment}
`;
const updatePostMutation = gql`
mutation updatePost($id: ID!, $title: String!) {
updatePost(id: $id, title: $title) {
...post
}
}
${postFragment}
`;
const deletePostMutation = gql`
mutation deletePost($id: ID!) {
deletePost(id: $id) {
id
}
}
`;
const uri = 'https://api.graph.cool/simple/v1/<project>';
const client = new ApolloClient({
link: new HttpLink({ uri }),
cache: new InMemoryCache()
});
// building a mobx store
const postsStore = new class {
constructor() {
extendObservable(this, {
get allPosts() {
return graphql({ client, query: allPostsQuery });
},
get error() {
return (this.allPosts.error && this.allPosts.error.message) || null;
},
get loading() {
return this.allPosts.loading;
},
get posts() {
return (this.allPosts.data && this.allPosts.data.allPosts) || [];
},
get count() {
return this.posts.length;
}
});
}
createPost = title =>
client
.mutate({
mutation: createPostMutation,
variables: { title },
refetchQueries: [{ query: allPostsQuery }]
})
.catch(error => console.error(error.message));
updatePost = (id, title) =>
client
.mutate({
mutation: updatePostMutation,
variables: { id, title },
refetchQueries: [{ query: allPostsQuery }]
})
.catch(error => console.error(error.message));
deletePost = id =>
client
.mutate({
mutation: deletePostMutation,
variables: { id },
refetchQueries: [{ query: allPostsQuery }]
})
.catch(error => console.error(error.message));
}();
// our main component
const Example = inject('postsStore')(
observer(
class extends Component {
create = () => this.props.postsStore.createPost('Hello World!');
update = (id, title) => {
const newTitle = prompt('Enter title', title);
if (newTitle && newTitle !== '')
this.props.postsStore.updatePost(id, newTitle);
};
delete = id => this.props.postsStore.deletePost(id);
render() {
const { error, loading, count, posts } = this.props.postsStore;
if (error) return <p>{error}</p>;
if (loading) return <p>Loading ..</p>;
if (count === 0)
return (
<div>
<button onClick={this.create}>Say Hello</button>
<p>No posts :(</p>
</div>
);
return (
<div>
<button onClick={this.create}>Say Hello</button>
<table style={{ width: '100%' }}>
<thead>
<tr>
<th>Index</th>
<th>ID</th>
<th>Title</th>
<th>Created at</th>
<th>Updated at</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{posts.map((post, index) => (
<tr key={index}>
<td>{index}</td>
<td>{post.id}</td>
<td>{post.title}</td>
<td>{new Date(post.createdAt).toLocaleString()}</td>
<td>{new Date(post.updatedAt).toLocaleString()}</td>
<td>
<button
onClick={this.update.bind(this, post.id, post.title)}>
Edit
</button>{' '}
<button onClick={this.delete.bind(this, post.id)}>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
}
)
);
const ExampleWithState = () => (
<Provider {...{ postsStore }}>
<Example />
</Provider>
);
export default ExampleWithState;
Example with subscriptions
import React, { Component } from 'react';
// create-react-app example
// yarn add apollo-client-preset graphql graphql-tag mobx mobx-apollo mobx-react
+// yarn add apollo-link apollo-link-ws apollo-utilities subscriptions-transport-ws
import gql from 'graphql-tag';
import graphql from 'mobx-apollo';
import { ApolloClient, HttpLink, InMemoryCache } from 'apollo-client-preset';
import { extendObservable } from 'mobx';
+import { getMainDefinition } from 'apollo-utilities';
import { inject, observer, Provider } from 'mobx-react';
+import { split } from 'apollo-link';
+import { WebSocketLink } from 'apollo-link-ws';
// schema built with Graphcool
// type Post implements Node {
// id: ID! @isUnique
// title: String!
// createdAt: DateTime!
// updatedAt: DateTime!
// }
-// fragments, queries and mutations
+// fragments, queries, mutations and subscriptions
const postFragment = gql`
fragment post on Post {
id
title
createdAt
updatedAt
}
`;
const allPostsQuery = gql`
{
allPosts {
...post
}
}
${postFragment}
`;
const createPostMutation = gql`
mutation createPost($title: String!) {
createPost(title: $title) {
...post
}
}
${postFragment}
`;
const updatePostMutation = gql`
mutation updatePost($id: ID!, $title: String!) {
updatePost(id: $id, title: $title) {
...post
}
}
${postFragment}
`;
const deletePostMutation = gql`
mutation deletePost($id: ID!) {
deletePost(id: $id) {
id
}
}
`;
+const postSubscription = gql`
+ subscription {
+ Post {
+ mutation
+ previousValues {
+ id
+ }
+ node {
+ ...post
+ }
+ }
+ }
+ ${postFragment}
+`;
const uri = 'https://api.graph.cool/simple/v1/<project>';
+const wsUri = 'wss://subscriptions.graph.cool/v1/<project>';
const client = new ApolloClient({
- link: new HttpLink({ uri }),
+ link: split(
+ ({ query }) => {
+ const { kind, operation } = getMainDefinition(query);
+ return kind === 'OperationDefinition' && operation === 'subscription';
+ },
+ new WebSocketLink({ uri: wsUri, options: { reconnect: true } }),
+ new HttpLink({ uri })
+ ),
cache: new InMemoryCache()
});
// building a mobx store
const postsStore = new class {
constructor() {
extendObservable(this, {
get allPosts() {
return graphql({ client, query: allPostsQuery });
},
get error() {
return (this.allPosts.error && this.allPosts.error.message) || null;
},
get loading() {
return this.allPosts.loading;
},
get posts() {
return (this.allPosts.data && this.allPosts.data.allPosts) || [];
},
get count() {
return this.posts.length;
}
});
+ this.subscribe('allPosts', 'Post', postSubscription);
}
+ subscribe = (prop, node, document) =>
+ this[prop].ref.subscribeToMore({
+ document,
+ updateQuery: (current, { subscriptionData }) => {
+ const prev = current[prop];
+ const next = subscriptionData.data[node];
+
+ if (next.mutation === 'CREATED')
+ return { [prop]: prev.concat([next.node]) };
+
+ if (next.mutation === 'UPDATED') {
+ const updated = prev.slice();
+ const index = updated.findIndex(({ id }) => id === next.node.id);
+ updated[index] = next.node;
+ return { [prop]: updated };
+ }
+
+ if (next.mutation === 'DELETED')
+ return {
+ [prop]: prev.filter(({ id }) => id !== next.previousValues.id)
+ };
+
+ return current;
+ }
+ });
createPost = title =>
client
.mutate({
mutation: createPostMutation,
variables: { title },
- refetchQueries: [{ query: allPostsQuery }]
})
.catch(error => console.error(error.message));
updatePost = (id, title) =>
client
.mutate({
mutation: updatePostMutation,
variables: { id, title },
- refetchQueries: [{ query: allPostsQuery }]
})
.catch(error => console.error(error.message));
deletePost = id =>
client
.mutate({
mutation: deletePostMutation,
variables: { id },
- refetchQueries: [{ query: allPostsQuery }]
})
.catch(error => console.error(error.message));
}();
// our main component
const Example = inject('postsStore')(
observer(
class extends Component {
create = () => this.props.postsStore.createPost('Hello World!');
update = (id, title) => {
const newTitle = prompt('Enter title', title);
if (newTitle && newTitle !== '')
this.props.postsStore.updatePost(id, newTitle);
};
delete = id => this.props.postsStore.deletePost(id);
render() {
const { error, loading, count, posts } = this.props.postsStore;
if (error) return <p>{error}</p>;
if (loading) return <p>Loading ..</p>;
if (count === 0)
return (
<div>
<button onClick={this.create}>Say Hello</button>
<p>No posts :(</p>
</div>
);
return (
<div>
<button onClick={this.create}>Say Hello</button>
<table style={{ width: '100%' }}>
<thead>
<tr>
<th>Index</th>
<th>ID</th>
<th>Title</th>
<th>Created at</th>
<th>Updated at</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{posts.map((post, index) => (
<tr key={index}>
<td>{index}</td>
<td>{post.id}</td>
<td>{post.title}</td>
<td>{new Date(post.createdAt).toLocaleString()}</td>
<td>{new Date(post.updatedAt).toLocaleString()}</td>
<td>
<button
onClick={this.update.bind(this, post.id, post.title)}>
Edit
</button>{' '}
<button onClick={this.delete.bind(this, post.id)}>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
}
)
);
const ExampleWithState = () => (
<Provider {...{ postsStore }}>
<Example />
</Provider>
);
export default ExampleWithState;
Recipes
- Pagination.
- Typescript Definitions, details here.
Note that the project description data, including the texts, logos, images, and/or trademarks,
for each open source project belongs to its rightful owner.
If you wish to add or remove any projects, please contact us at [email protected].