smallorange-graphql-react-prefetcher

1.0.9 • Public • Published

CircleCI

Small Orange Graphql React Prefetcher

Usage

You need provide a graphql transport layer that returns an Observable like. It would be server side (like this sample), or an ajax function which talks with a graphql backend, but its important to keep same args input of the sample below, and might returns an Observable with the result:

	import {
	    graphql,
	    GraphQLSchema,
	    GraphQLObjectType,
	    GraphQLString,
	    GraphQLInt
	} from 'graphql';
	import {
	    Observable
	} from 'rxjs';

	const schema = new GraphQLSchema({
	    query: new GraphQLObjectType({
	        name: 'Query',
	        fields: {
	            name: {
	                type: GraphQLString,
	                args: {
	                    age: {
	                        type: GraphQLInt
	                    }
	                },
	                resolve: (root, {
	                    age
	                }, context, info) => {
	                    return age ? `Rohde - ${age}` : 'Rohde';
	                }
	            }
	        }
	    }),
	});

	export graphQlRunner = args => {
        const {
            query,
            root = {},
            context = {},
            variables = {}
        } = args;

        if (!query) {
            return Observable.throw(new Error('No query provided.'));
        }

        return Observable.create(subscriber => {
            graphql(schema, query, root, context, variables)
                .then(response => {
                    if (response.errors) {
                        return subscriber.error(new Error(response.errors.join()));
                    }

                    subscriber.next(response);
                    subscriber.complete();
                });
        });
    }

React components can have three static properties or methods, "queries", "dependencies" and "info":

	// set component queries
	queries: {[queryName: string]: {query: string, args?: object, callback?: function}}
	queries: {[queryName: string]: Observable<{query: string, args?: object, callback?: function}>}
	queries: {[queryName: string]: args => {query: string, args?: object, callback?: function}}
	queries: {[queryName: string]: args => Observable<{query: string, args?: object, callback?: function}>}
	queries(props): {[queryName: string]: {query: string, args?: object, callback?: function}}
	queries(props): {[queryName: string]: Observable<{query: string, args?: object, callback?: function}>}
	queries(props): {[queryName: string]: args => {query: string, args?: object, callback?: function}}
	queries(props): {[queryName: string]: args => Observable<{query: string, args?: object, callback?: function}>}
	
	// set component dependencies
	dependencies(props): {[dependencyName: string]: {
		component: React.Component | string,
		args?: {
			[queryName: string]: {
				[arg: string]: any
			}	
		},
		props?: {
			[arg: string]: any
		}
	}}
	dependencies(props): {[dependencyName: string]: Observable<{
		component: React.Component | string,
		args?: {
			[queryName: string]: {
				[arg: string]: any
			}	
		},
		props?: {
			[arg: string]: any
		}
	}>}
	dependencies: {[dependencyName: string]: {
		component: React.Component | string,
		args?: {
			[queryName: string]: {
				[arg: string]: any
			}	
		},
		props?: {
			[arg: string]: any
		}
	}}
	dependencies: {[dependencyName: string]: Observable<{
		component: React.Component | string,
		args?: {
			[queryName: string]: {
				[arg: string]: any
			}	
		},
		props?: {
			[arg: string]: any
		}
	}>}
	dependencies: {[dependencyName: string]: Array<{
		component: React.Component | string,
		args?: {
			[queryName: string]: {
				[arg: string]: any
			}	
		},
		props?: {
			[arg: string]: any
		}
	}>}
	
	// export some value to prefetcher
	info: object;
	info(props, resolvedQueries): object;

React Component Sample

	export class Child extends React.Component {
		static queries(props){
			return {
				name: `name`
				dog: `dog`
			}
		}

		render() {
			const {
				queries = {}
			} = this.props;

			return (queries.dog && queries.name )? <h1>{queries.dog} belongs to {queries.name}</h1> : null;
		}
	}

	export class App extends React.Component {
		static queries = {
			name: args => {
				query: `name(age: $age)`,
				args: {
					age: args.age
				}
			}
		};

		static dependencies(props){
			return {
				child: {
					component: 'Child'
				},
				children: [{
					component: 'Child'
				}, {
					component: 'Child'
				}]
			};
		}

		static info = {
			title: 'Page Title'
		};

		render() {
			const {
				queries = {},
				dependencies = {},
				args = {}
			} = this.props;

			const Child = dependencies.child || null;

			return (
				<section>
					<h1>{queries.name}</h1>
					<h2>{args.customArgs}</h2>
					
					{Child ? <Child/> : null}

					{_.map(dependencies.children, (Component, key) => (
						Component ? <Component key={key}/> : null
					))}
				</section>
			);
		}
	}

Prefetcher usage

	import {
		renderToStaticMarkup
	} from 'react-dom/server';
	import {
		Prefetcher
	} from 'smallorange-graphql-react-prefetcher';

	import graphql from 'graphqlTransporter'; // see above
	import * as components from 'components';

	const descriptor = {
		app: {
			component: 'App' || components.App,
			args: {
				name: {
					age: 20
				}
			}
		},
		child: {
			component: 'Child' || components.Child
		}
	};

	const prefetcher = new Prefetcher(graphql, components /* just provide this if you intend to lookup components via strings, in descriptor */);

	prefetcher.run(descriptor.app)
		.subscribe(response => {
			// when there is info exported, prefetcher returns and object containing info, and component
			const {
				component: Component,
				info
			} = response;

			console.log(info); // info exported from "static info"

			renderToStaticMarkup(<Component/>); // Component with prefetched data from queries and resolved dependnecies
		});

	// OOOR		
	prefetcher.run(descriptor.child)
		.subscribe(response => {
			// when there is no info exported, prefetcher returns just the component
			const Component = response;

			renderToStaticMarkup(<Component/>); // Component with prefetched data from queries
		});

	// OOOR you can optionally run a single query with

	prefetcher.query(descriptor.app.queries.name)
		.subscribe(/* you know what to do */);

Final Words

If you have any questions, see the specs, otherwise contact me at felipe@smallorange.co. I intend to write a better documentation, as soon I have more time.

Readme

Keywords

none

Package Sidebar

Install

npm i smallorange-graphql-react-prefetcher

Weekly Downloads

1

Version

1.0.9

License

ISC

Last publish

Collaborators

  • feliperohde