diff --git a/CHANGELOG.md b/CHANGELOG.md
index aca382ebbe9..84aa51e3901 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+## Apollo Client 3.3.8
+
+### Bug Fixes
+
+- Catch updates in `useReactiveVar` with an additional check.
+ [@jcreighton](https://github.com/jcreighton) in [#7652](https://github.com/apollographql/apollo-client/pull/7652)
+
## Apollo Client 3.3.7
### Bug Fixes
diff --git a/src/react/hooks/__tests__/useReactiveVar.test.tsx b/src/react/hooks/__tests__/useReactiveVar.test.tsx
index 7c755d86d0e..20754b0da70 100644
--- a/src/react/hooks/__tests__/useReactiveVar.test.tsx
+++ b/src/react/hooks/__tests__/useReactiveVar.test.tsx
@@ -169,4 +169,72 @@ describe("useReactiveVar Hook", () => {
console.error = error;
}).then(resolve, reject);
});
+
+ describe("useEffect", () => {
+ itAsync("works if updated higher in the component tree", async (resolve, reject) => {
+ const counterVar = makeVar(0);
+
+ function ComponentOne() {
+ const count = useReactiveVar(counterVar);
+
+ useEffect(() => {
+ counterVar(1);
+ }, []);
+
+ return (
{count}
);
+ }
+
+ function ComponentTwo() {
+ const count = useReactiveVar(counterVar);
+
+ return ({count}
);
+ }
+
+ const { getAllByText } = render(
+ <>
+
+
+ >
+ );
+
+ await wait(() => {
+ expect(getAllByText("1")).toHaveLength(2);
+ });
+
+ resolve();
+ });
+
+ itAsync("works if updated lower in the component tree", async (resolve, reject) => {
+ const counterVar = makeVar(0);
+
+ function ComponentOne() {
+ const count = useReactiveVar(counterVar);
+
+ return ({count}
);
+ }
+
+ function ComponentTwo() {
+ const count = useReactiveVar(counterVar);
+
+ useEffect(() => {
+ counterVar(1);
+ }, []);
+
+ return ({count}
);
+ }
+
+ const { getAllByText } = render(
+ <>
+
+
+ >
+ );
+
+ await wait(() => {
+ expect(getAllByText("1")).toHaveLength(2);
+ });
+
+ resolve();
+ });
+ });
});
diff --git a/src/react/hooks/useReactiveVar.ts b/src/react/hooks/useReactiveVar.ts
index f348ac7bf14..a53af0750b5 100644
--- a/src/react/hooks/useReactiveVar.ts
+++ b/src/react/hooks/useReactiveVar.ts
@@ -18,5 +18,15 @@ export function useReactiveVar(rv: ReactiveVar): T {
// const mute = rv.onNextChange(setValue);
// return () => mute();
// }, [value])
+
+ // We check the variable's value in this useEffect and schedule an update if
+ // the value has changed. This check occurs once, on the initial render, to avoid
+ // a useEffect higher in the component tree changing a variable's value
+ // before the above useEffect can set the onNextChange handler. Note that React
+ // will not schedule an update if setState is called with the same value as before.
+ useEffect(() => {
+ setValue(rv())
+ }, []);
+
return value;
}