#client react to change

12 messages · Page 1 of 1 (latest)

weak terrace
#

how can i fire a single function in react whenever the value of data from a convex query changes

proper impBOT
#

Hi @weak terrace. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

To fire a single function in React whenever the value of data from a Convex query changes, you have two main approaches:

1. Using useEffect with useQuery

If you are using the standard Convex React client, you can use the useQuery hook to subscribe to your query, and then use a useEffect to react to changes in the query result:

import { useQuery } from "convex/react";
import { api } from "../convex/_generated/api";
import { useEffect } from "react";

export function MyComponent() {
  const data = useQuery(api.functions.myQuery, { /* args */ });

  useEffect(() => {
    if (data !== undefined) {
      // This function runs every time `data` changes
      myFunction(data);
    }
  }, [data]);

  return <div>{/* ... */}</div>;
}

This pattern ensures your function is called every time the query result updates reactively in response to backend changes Fetching data.


2. Using watchQuery for Fine-Grained Control

If you need more control (for example, to manage subscriptions manually or avoid React re-renders), you can use the lower-level watchQuery API:

import { useConvex } from "convex/react";
import { api } from "../convex/_generated/api";
import { useEffect } from "react";

export function MyComponent({ param1, param2 }) {
  const convex = useConvex();

  useEffect(() => {
    const watch = convex.watchQuery(api.functions.myQuery, { param1, param2 });
    const unsubscribe = watch.onUpdate(() => {
      const newValue = watch.localQueryResult();
      if (newValue !== undefined) {
        myFunction(newValue);
      }
    });
    return () => unsubscribe();
  }, [convex, param1, param2]);
#

return <div>{/* ... */}</div>;
}

This approach gives you direct access to the subscription and lets you call your function exactly when the query result changes, without relying on React state updates [Watch<T> interface](<https://docs.convex.dev/api/interfaces/react.Watch>) [Discord support thread](<https://discord.com/channels/1019350475847499849/1330893800868155434>).

---

**Summary:**  
- Use `useEffect` with `useQuery` for most cases.
- Use `watchQuery` for advanced scenarios where you need manual subscription management or want to avoid React re-renders.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
#

@weak terrace Kapa.ai is still learning and improving, please let me know how I did by reacting below.

weak terrace
#

@proper imp what if i want to compare the last data to the current/new data and fire a toast or equivalent if it is +1 higher?

proper impBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

To compare the last data to the current/new data from a Convex query and fire a toast (or similar notification) if the value increases by +1, you can use the standard React pattern with useQuery and useEffect, along with a useRef to keep track of the previous value.

Here’s how you can do it:

import { useQuery } from "convex/react";
import { api } from "../convex/_generated/api";
import { useEffect, useRef } from "react";

export function MyComponent() {
  const data = useQuery(api.counter.getCounter, { counterName: "clicks" });
  const prevData = useRef();

  useEffect(() => {
    if (prevData.current !== undefined && data !== undefined) {
      if (data === prevData.current + 1) {
        // Fire your toast here
        showToast("Counter increased by 1!");
      }
    }
    prevData.current = data;
  }, [data]);

  return <div>{data ?? "Loading..."}</div>;
}
  • prevData holds the previous value of data.
  • The useEffect runs every time data changes.
  • If the new value is exactly one higher than the previous value, you trigger your toast.

This approach is directly compatible with Convex’s useQuery reactivity, as shown in the Convex React documentation.

If you need more control (for example, to avoid React re-renders), you could use the watchQuery API and compare the values inside the onUpdate callback, as described in the Discord support thread.

Let me know if you need an example using watchQuery!

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@weak terrace Kapa.ai is still learning and improving, please let me know how I did by reacting below.

weak terrace
#

@proper imp is there a hook to use watchQuery or do i just have to call it on the client instance? what happens if i have "watch" on this query but also am subscribed to it via useQuery?

proper impBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

There is no built-in React hook for watchQuery in the Convex React client. If you want to use watchQuery, you need to call it directly on the ConvexReactClient instance (which you can access via the useConvex() hook) and manage its lifecycle yourself, typically inside a useEffect ConvexReactClient methods.

Example usage:

const convex = useConvex();
useEffect(() => {
  const watch = convex.watchQuery(api.myQuery, { /* args */ });
  const unsubscribe = watch.onUpdate(() => {
    // handle update
  });
  return () => unsubscribe();
}, [convex, /* args */]);

If you have both a watch on a query and are also subscribed to it via useQuery:

  • Both subscriptions are independent. The Convex client will manage each subscription separately.
  • However, if both subscriptions are for the same query with the same arguments, Convex will optimize and only maintain a single underlying subscription to the backend for that query/args combination. Both your watchQuery and useQuery will receive updates, but you are responsible for managing their respective handlers in your code Discord support thread.

In the React client if you subscribe to the same query twice you will not get an automatic callback on the second subscription, so you may want to check for the value synchronously and call it.
— Discord support thread

So, you can safely use both, but be aware of how you handle updates and avoid redundant logic if both are active for the same query and arguments.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: