Reactive State Management with Apollo Client React

mohit thakur
Geek Culture
Published in
3 min readApr 14, 2021

--

Who is the audience?

Anyone struggling with React applications component hell and prop drilling will find this article helpful.

What you should know beforehand?

Should be familiar with React and Redux or Ngrx if you come from an angular background.

What is the Problem?

There are lots of problems with state management with Apollo, worked on both angular and React it feels like just caching API doesn't mean you have done state management. You should be able to consume data easily with any state management library. Apollo is very poor at client-side state management.

What is the client-side state?

The data is not present on the server but is required only in the front end to take actions on the view.

When you try to set a global modal and you want to show and hide this on some condition, you don’t keep this flag on server but is managed in client side.

Apollo Client Reactive Var to Rescue?

If you have worked with Apollo it says everything is magic, believe me, it is not. If you come from Redux background, you can already understand what I mean.

Enough of lecturing lets get our hands dirty

Lets try make a currency search component, where we can enter to filter out currency by their name initials.

Folder Structure

Lets see example container

// inteligent container to do all the data interaction like a controllerimport React, { Fragment, useEffect } from "react";
import { Col, Container, Row } from "react-bootstrap";
import { exampleState } from "../localstate/example";
import { SearchExample } from "./search";
import { useApolloClient, useQuery, useReactiveVar } from "@apollo/client";
import { GET_RATES, GET_RATES_PLUS_CLIENT } from "./queries/queries";
import { Item } from "./item";
export function ExampleContainer(props) {
const state = useReactiveVar(exampleState);
const client = useApolloClient();const { loading, error, data } = useQuery(GET_RATES);useEffect(() => {
console.log(state, " state changed");
client.query({ query: GET_RATES_PLUS_CLIENT }).then((data) => {
console.log(data, " got this data using query");
});
}, [state.searchString]);
if (loading) return <p> loading</p>;
if (error) return <p> error</p>;
return (
<Fragment>
<Container>
<Row>
<Col xs={12}>
{state.searchString}
<SearchExample />
</Col>
</Row>
<Row>
{data.rates
.filter((f) =>
f.currency.includes(state.searchString.toUpperCase())
)
.map((item) => {
return <Item currency={item.currency} />;
})}
</Row>
</Container>
</Fragment>
);
}

if you take a closer look at above component you will see less props being passed around , what we are using instead is a Reactive Var from Apollo Client to share the client side state among component.

So no call back hell anymore.

Lets take a look at client side Reactive file

import { makeVar } from "@apollo/client";// shape of your local state
export interface ExampleState {
searchString: string;
items: Number[];
orgid: Number;
SelectAll: Boolean;
}
const initialState = {
searchString: "",
items: [],
orgid: null,
SelectAll: false
};
export const exampleState = makeVar<ExampleState>(initialState);

I know what you are thinking it looks like a behavior subject and it is quite similar, it is based on Zen observable , little brother of Rxjs.

How to consume Reactive Var, Apollo gives you useReactiveVar Hook

const state = useReactiveVar(exampleState);

Now any component that has this state can listen to changes in state easily with effects.

Our container component can listen to changes in search string and filter the list of currencies

useEffect(() => {
console.log(state, " state changed");
client.query({ query: GET_RATES_PLUS_CLIENT }).then((data) => {
console.log(data, " got this data suing query");
});
}, [state.searchString]);

Any change to state.searchString will trigger a new search .

That’s it no callbacks , happy coding. Can check out working example at

here

Leave a clap if you enjoyed this example :)

--

--