This page covers how to manage your local (client-side) state. If you're looking for information about querying or mutating data through a server, you can read more about that here.
Falcon comes with Apollo Client for client-side state management when you use
create-falcon-app to generate a new application. Apollo Client will be pre-configured and does not require any additional setup. You can start using it right away.
The short version
If you already know how to use Apollo Client, you pretty much know how to use it with Falcon. If you need a refresher, continue to the long version or the Apollo documentation. We also provide a few additional components you can use.
Your initialized local state and the resolvers go in
The long version
This will go in-depth about how to use Apollo for managing the client state of your Falcon application.
If you're unfamiliar with GraphQL queries it is recommended to check out this guide.
Local state management
Apollo is great when using GraphQL to fetch data on your front-end, but you can also use Apollo Client to do local state management, just like you would use the React Context API, MobX or Redux. You can use those other options as well, but using Apollo Client for local state management is ideal because your Apollo cache will be the single source of truth in your application's front-end.
You can read more about local state management with Apollo Client here. Since hooks are not supported below version 2.0 of Falcon, you might need to use the examples with Render Prop. You can use the dropdown above their code examples to change the examples from hooks to render props.
Using and updating local client state
When using local client state, you need to write resolvers to query and mutate the data. You can read more about that in Apollo's documentation about local resolvers.
You can use
client/src/clientState.js to define your client's initial state and resolvers.
You can use
cache.writeData for one-off mutations that don't depend on the data that's currently in the cache. This is an alternative for writing a
Mutation component. More on that at writing resolvers for local client state.
It's important to note that direct writes are not implemented as GraphQL mutations under the hood, so you shouldn't include them in your schema. They also do not validate that the data you're writing to the cache is in the shape of valid GraphQL data. If either of these features are important to you, you should opt to use a local resolver instead. - Apollo Docs
You can then subscribe to this data with a
Query component. The
@client directive in the GraphQL query lets Apollo Client know to fetch this data locally, as opposed to fetching it from a server. All cache writes and reads are synchronous, so you don't have to worry about loading state.
The other way is by creating a
Mutation component with a GraphQL mutation that calls a local client-side resolver. Writing a
Mutation is recommended by Apollo when your mutation depends on existing values in the cache. To do this you need to specify a function in your local resolver map, located in
Writing resolvers for local client state
First, you should write the GraphQL query. In this example we use a sidebar component to showcase how you would write your mutation resolver to toggle its
Then we write our resolver functions so we can change the
Note: You need to return
null here since all GraphQL types are nullable by default.
At this point you are ready to write your
Mutation component which will expose a function to your React components you can use to toggle the Sidebar's
Then you can use the components like this to manage the state of your sidebar component:
Then, somewhere in your application:
In the end
<Sidebar /> only cares about the props it receives and all the other logic is abstracted away. This is a lot of work for just toggling the
isOpen state for a sidebar, but as you can imagine this is great for abstracting away more complicated interactions with your application's data.
Querying local state
Querying the local state works just like fetching data from a GraphQL server. The only difference is the
@client directive you already saw in the section about mutating client state above.
@client tells a
Query component that the data should be pulled from the Apollo Client cache or resolved using pre-defined local resolvers.
Resetting your store
From the Apollo documentation:
Sometimes you may need to reset the store in your application, when a user logs out for example. If you call
client.resetStoreanywhere in your application, you will likely want to initialize your cache again. You can do this using the
client.onResetStoremethod to register a callback that will call
Local data query flow
Here's an example from the Apollo documentation about a query that fetches both local client state with
@client and some data from a GraphQL server.
@client into remote queries
Adding new GraphQL object types to your resolver map is a way to combine local and remote queries. To do this you can add a new key like
Member in your
The result of this is that the
isLoggedIn property will be available when you query a
Member. In this case the
@client directive is required to let Apollo Client know this data should be returned from your client as opposed to getting fetched from a server.
This allows you to mix data from a server as well as data from your client in a single query.
For more information, continue reading on the Apollo Documentation about intregrating
@client into remote queries.
There are some things to consider when integrating
@client into remote queries.
Forcing resolvers to run
@clientparts on every request. Use this carefully, as it can impact performance.