ConstonData instead of useEffectIf you want to react to incoming data, please use the onData option instead of useEffect.
State updates you make inside a useEffect hook might cause additional rerenders, and useEffect is mostly meant for side effects of rendering, not as an event handler.
State updates made in an event handler like onData might - depending on the React version - be batched and cause only a single rerender.
Consider the following component:
export function Subscriptions() {
const { data, error, loading } = useDataClientSubscription(query);
const [accumulatedData, setAccumulatedData] = useState([]);
useEffect(() => {
setAccumulatedData((prev) => [...prev, data]);
}, [data]);
return (
<>
{loading && <p>Loading...</p>}
{JSON.stringify(accumulatedData, undefined, 2)}
</>
);
}
Instead of using useEffect here, we can re-write this component to use the onData callback function accepted in useSubscription's options object:
export function Subscriptions() {
const [accumulatedData, setAccumulatedData] = useState([]);
const { data, error, loading } = useDataClientSubscription(
query,
{
onData({ data }) {
setAccumulatedData((prev) => [...prev, data])
}
}
);
return (
<>
{loading && <p>Loading...</p>}
{JSON.stringify(accumulatedData, undefined, 2)}
</>
);
}
⚠️ Note: The
useSubscriptionoptiononDatais available in Apollo Client >= 3.7. In previous versions, the equivalent option is namedonSubscriptionData.
Now, the first message will be added to the accumulatedData array since onData is called before the component re-renders. React 18 automatic batching is still in effect and results in a single re-render, but with onData we can guarantee each message received after the component mounts is added to accumulatedData.
const COMMENTS_SUBSCRIPTION = gql`
subscription OnCommentAdded($repoFullName: String!) {
commentAdded(repoFullName: $repoFullName) {
id
content
}
}
`;
function DontReadTheComments({ repoFullName }) {
const {
data: { commentAdded },
loading,
} = useDataClientSubscription(COMMENTS_SUBSCRIPTION, { variables: { repoFullName } });
return <h4>New comment: {!loading && commentAdded.content}</h4>;
}
Refer to the Subscriptions section for a more in-depth overview of
useSubscription.