Skip to content
This repository has been archived by the owner on Nov 20, 2020. It is now read-only.

Commit

Permalink
Merge pull request #128 from idkjs/master
Browse files Browse the repository at this point in the history
add Fragments example and Readme notes
  • Loading branch information
mbirkegaard authored Jun 20, 2020
2 parents f6d4a38 + b3d29f1 commit a51516f
Show file tree
Hide file tree
Showing 7 changed files with 955 additions and 486 deletions.
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Reason bindings for the official [@apollo/react-hooks](https://www.npmjs.com/pac
- [useMutation :arrow_up:](#usemutation-arrowup)
- [useSubscription :arrow_up:](#usesubscription-arrowup)
- [Cache :arrow_up:](#cache-arrowup)
- [Fragment :arrow_up:](#fragment-arrowup)
- [Getting it running](#getting-it-running)
- [Contributors ✨](#contributors-%e2%9c%a8)

Expand Down Expand Up @@ -383,6 +384,39 @@ If using directives like `@bsRecord`, `@bsDecoder` or `@bsVariant` in `graphql_p

By default, apollo will add field `__typename` to the queries and will use it to normalize data and manipulate cache (see [normalization](https://www.apollographql.com/docs/react/advanced/caching/#normalization)). This field won't exist on parsed reason objects, since it is not included in the actual query you write, but is added by apollo before sending the query. Since `__typename` is crucial for the cache to work correctly, we need to read data from cache in its raw unparsed format, which is achieved with `readQuery` from `ApolloClient.ReadQuery` defined in `reason-apollo`.


## Fragment [:arrow_up:](#table-of-contents)

Using [fragments](https://www.apollographql.com/docs/react/data/fragments/).

Fragments can be defined and used like this:

```reason
// Fragments.re
module PersonFragment = [%graphql
{|
fragment person on Person {
id
name
age
}
|}
];
```

```reason
module PersonsQuery = [%graphql
{|
query getAllPersons {
...Fragments.PersonFragment.Person
}
|}
];
```

See [examples/persons/src/fragments/LoadMoreFragments.re](examples/persons/src/fragments/LoadMoreFragments.re).

## Getting it running

```sh
Expand Down
188 changes: 160 additions & 28 deletions examples/persons/build/Index.js

Large diffs are not rendered by default.

43 changes: 41 additions & 2 deletions examples/persons/src/Root.re
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ let filterName = "Bob";

type example =
| LoadMore
| LoadMoreFragments
| SubscribeToMore;

[@react.component]
Expand Down Expand Up @@ -43,6 +44,11 @@ let make = () => {
onClick={_ => setActiveExample(_ => SubscribeToMore)}>
{React.string("Subscribe to More")}
</button>
<button
className={getTabClassName(LoadMoreFragments)}
onClick={_ => setActiveExample(_ => LoadMoreFragments)}>
{React.string("Load More Fragments")}
</button>
</div>
<div className="tab-content">
{switch (activeExample) {
Expand All @@ -54,13 +60,46 @@ let make = () => {
refetchQueries=editPersonRefetchQueries
update=editPersonUpdate
/>
<h3> {React.string("FilterByAge.re")} </h3>
<FilterByAge age=filterAgeLimit />
<FilterByAgeErrorHandling age=filterAgeLimit />
<section>
<title>
{React.string("FilterByAgeErrorHandling.re")}
</title>
<FilterByAgeErrorHandling age=filterAgeLimit />
</section>
<h3> {React.string("FilterByAgeFragment.re")} </h3>
<FilterByAgeFragment age=filterAgeLimit />
<h3> {React.string("FilterByNameCache.re")} </h3>
<FilterByNameCache name=filterName />
</div>
</div>
<LoadMore />
</>
| LoadMoreFragments =>
<>
<div className="edit-person-container">
<div className="edit-person">
<EditPerson
refetchQueries=editPersonRefetchQueries
update=editPersonUpdate
/>
<h3> {React.string("FilterByAge.re")} </h3>
<FilterByAge age=filterAgeLimit />
<section>
<title>
{React.string("FilterByAgeErrorHandling.re")}
</title>
<FilterByAgeErrorHandling age=filterAgeLimit />
</section>
<h3> {React.string("FilterByAgeFragment.re")} </h3>
<FilterByAgeFragment age=filterAgeLimit />
<h3> {React.string("FilterByNameCache.re")} </h3>
<FilterByNameCache name=filterName />
</div>
</div>
<LoadMoreFragments />
</>
| SubscribeToMore =>
<>
<div className="add-person-container">
Expand All @@ -71,4 +110,4 @@ let make = () => {
}}
</div>
</>;
};
};
37 changes: 37 additions & 0 deletions examples/persons/src/fragments/FilterByAgeFragment.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
open Fragments;
open ApolloHooks;

module PersonsOlderThanQuery = [%graphql
{|
query getPersonsOlderThan($age: Int!) {
allPersons(filter: { age_gte: $age } ) {
...PersonFragment.Person
}
}
|}
];

[@react.component]
let make = (~age) => {
let (simple, _full) =
useQuery(
~variables=PersonsOlderThanQuery.makeVariables(~age, ()),
PersonsOlderThanQuery.definition,
);

<div>
{switch (simple) {
| Loading => <p> {React.string("Loading...")} </p>
| Data(data) =>
<h3>
{"There are "
++ (data##allPersons->Belt.Array.length |> string_of_int)
++ " people older than "
++ string_of_int(age)
|> React.string}
</h3>
| NoData
| Error(_) => <p> {React.string("Error")} </p>
}}
</div>;
};
48 changes: 48 additions & 0 deletions examples/persons/src/fragments/Fragments.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// example of creating a fragment on a type available from your grapqlql-ppx types.

// In this contrived example, here instead of using the following as seen in the `FilterByAge.re`
// module PersonsOlderThanQuery = [%graphql
// {|
// query getPersonsOlderThan($age: Int!) {
// allPersons(filter: { age_gte: $age } ) {
// id
// }
// }
// |}
// ];

// we can use the following as seen in `FilterByAgeFragment.re`
// ```
// module PersonsOlderThanQuery = [%graphql
// {|
// query getPersonsOlderThan($age: Int!) {
// allPersons(filter: { age_gte: $age } ) {
// ...PersonFragment.Person
// }
// }
// |}
// ];
// ```
module PersonFragment = [%graphql
{|
fragment person on Person {
id
name
age
}
|}
];
module PersonIdFragment = [%graphql
{|
fragment person on Person {
id
}
|}
];
module PersonAgeFragment = [%graphql
{|
fragment person on Person {
age
}
|}
];
65 changes: 65 additions & 0 deletions examples/persons/src/fragments/LoadMoreFragments.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
module GetAllPersonsQuery = [%graphql
{|
query getAllPersons($skip: Int!, $first: Int!) {
allPersons(skip: $skip, first: $first) {
...Fragments.PersonFragment.Person
}
}
|}
];

let personsPerPage = 5;

[@react.component]
let make = () => {
let (_simple, full) =
ApolloHooks.useQuery(
~variables=
GetAllPersonsQuery.makeVariables(~skip=0, ~first=personsPerPage, ()),
~notifyOnNetworkStatusChange=true,
GetAllPersonsQuery.definition,
);

let handleLoadMore = _ => {
let skip =
switch (full) {
| {data: Some(data)} => data##allPersons->Belt.Array.length
| _ => 0
};

full.fetchMore(
~variables=
GetAllPersonsQuery.makeVariables(~skip, ~first=personsPerPage, ()),
~updateQuery=[%bs.raw
{|
function(prevResult, { fetchMoreResult, ...rest }) {
if (!fetchMoreResult) return prevResult;
return {
...fetchMoreResult,
allPersons: prevResult.allPersons.concat(fetchMoreResult.allPersons)
};
}
|}
],
(),
)
|> ignore;
};

<div className="person-list">
{switch (full) {
| {loading: true, data: None} => <p> {React.string("Loading...")} </p>
| {data: Some(data)} =>
<>
<Persons persons={data##allPersons} />
<button
onClick=handleLoadMore disabled={full.networkStatus === FetchMore}>
{React.string("Load more")}
</button>
</>
| {error: Some(_)} => <p> {React.string("Error")} </p>
| {error: None, data: None, loading: false} =>
<p> {React.string("Not asked")} </p>
}}
</div>;
};
Loading

0 comments on commit a51516f

Please sign in to comment.