cultofcoders:grapher-react

v0.1.5Published 5 years ago

This package has not had recent updates. Please investigate it's current state before committing to using it in your project.

Grapher React Components

Using the cultofcoders:grapher query component in React.

Installation

meteor add cultofcoders:grapher-react

Signature

1withQuery(() => query, options)(Component);

The first function needs to return a valid Query or NamedQuery from Grapher.

1// This is a query
2const query = createQuery({
3    users: {
4        emails: 1,
5    },
6});
7
8// This is a named query
9const query = createQuery('usersWithEmails', {
10    users: {
11        emails: 1,
12    },
13});

Options

Simple Usage

1import React from 'react';
2import { withQuery } from 'meteor/cultofcoders:grapher-react';
3
4const PostList = ({ data, isLoading, error }) => {
5    if (isLoading) {
6        return <div>Loading</div>;
7    }
8
9    if (error) {
10        return <div>{error.reason}</div>;
11    }
12
13    return (
14        <div>
15            {data.map(post => (
16                <li key={post._id}>{post.title}</li>
17            ))}
18        </div>
19    );
20};
21
22export default withQuery(props => {
23    return getPostLists.clone();
24})(PostList);

Props Received

Below are the properties received by the component we wrap, in the example above, that's PostList

Let's react!

The first example uses the query non-reactively (because that is the default). But let's say you want your query to be reactive (react to changes in the database)

1// ...
2export default withQuery(
3    props => {
4        return getPostLists.clone();
5    },
6    { reactive: true },
7)(PostList);

As mentioned above, the props received are passed down to the component we wrap, meaning:

1const PostList = ({ data, something }) => {
2    return <div>Something is true!</div>;
3};
4
5const Container = withQuery(
6    props => {
7        return getPostLists.clone();
8    },
9    { reactive: true },
10)(PostList);
11
12export default function() {
13    return <Container something={true} />;
14}

The query object is also passed down as a prop, so, if you ever need it you can access it from there.

For a non-reactive query, we also pass refetch function as prop, which simply refetches the query from the database, and updates the components properly:

1import React from 'react';
2import { withQuery } from 'meteor/cultofcoders:grapher-react';
3
4const PostList = ({ data, isLoading, error, refetch }) => {
5    return (
6        <div>
7            <a onClick={refetch}>Reload the data</a>
8            {/* Rest of the component */}
9        </div>
10    );
11};
12
13export default withQuery(
14    props => {
15        return getPostLists.clone();
16    },
17    { reactive: false },
18)(PostList);

If you container wraps a single object, and not a list of objects, you can configure your query like this:

1const UserProfile = ({ data, isLoading, error }) => {
2    return <div>{data.email}</div>;
3};
4
5export default withQuery(
6    props => {
7        return getUserProfile.clone({ userId: props.userId });
8    },
9    {
10        single: true,
11    },
12)(UserProfile);

You will find yourself repeating the same code over and over again for when the query is loading or it has an error. For this you can do:

1function ErrorComponent({ error }) {
2    return <div>{error.reason}</div>;
3}
4
5function LoadingComponent() {
6    return <div>Please wait...</div>;
7}
8
9const UserProfile = ({ data }) => {
10    return <div>{data.email}</div>;
11};
12
13export default withQuery(
14    props => {
15        return getUserProfile.clone({ userId: props.userId });
16    },
17    {
18        single: true,
19        errorComponent: ErrorComponent,
20        loadingComponent: LoadingComponent,
21    },
22)(UserProfile);

The UserProfile component will not render if it's loading or it errored.

To make things even more simple, you can globally define these rules, and all the components by default will have those options.

1import { setDefaults } from 'meteor/cultofcoders:grapher-react';
2
3setDefaults({
4    reactive: false, // you can default it to true
5    single: false, // doesn't make sense to default this to true
6    errorComponent: ErrorComponent,
7    loadingComponent: LoadingComponent,
8});

You can override the defaults at the withQuery level, for example you want different error and loading components, you can simply do:

1export default withQuery(
2    props => {
3        return getUserProfile.clone({ userId: props.userId });
4    },
5    {
6        errorComponent: null,
7        loadingComponent: AnotherLoadingComponent,
8    },
9)(UserProfile);