React Integration
TeamPlay integrates seamlessly with React, allowing you to build reactive user interfaces with ease. This guide will show you how to use TeamPlay in your React components.
The observer() Higher-Order Component
To use TeamPlay signals in a React component, you need to wrap your component with the observer() function:
Why do we need observer()?
The observer() function does two important things for your component:
- It allows the component to "see" changes in TeamPlay signals and automatically re-render when those signals change.
- It automatically wraps your component in a Suspense boundary, handling loading states for you.
Using useSub() for Data Subscriptions
When you want to subscribe to data from the server in a React component, use the useSub() hook with an object-tree signal:
How useSub() Works with Suspense
useSub() works with the Suspense functionality that observer() provides:
- It starts fetching the data from the server.
- While fetching, it "suspends" the component.
- The
observer()wrapper shows a loading state. - Once the data is ready, the component renders with the data.
Async subscriptions
If the component should render its own loading state instead of suspending, use
useAsyncSub():
Batch subscriptions
Use useBatchSub() when several subscriptions should become ready together.
Each batch subscription is declared first, then a final no-argument
useBatchSub() closes the Suspense barrier:
useBatchSub() keeps TeamPlay's normal defer default. Pass { defer: false }
only when the component needs immediate resubscription timing, such as when
migrating legacy synchronous batch screens.
useBatchSub(signal, params, options) is syntax sugar for
useSub(signal, params, { ...options, batch: true, async: false }). The barrier
can also be closed with the lower-level form
useSub(undefined, undefined, { batch: true }), but useBatchSub() is the
recommended spelling in application code.
Avoid legacy hook names like useDoc, useQuery, useBatchDoc, and
useBatchQuery in new code. The public API is the object-tree subscription API:
useSub, useAsyncSub, and useBatchSub.
Creating and Waiting for Documents
Sometimes, you might need to create a document if it doesn't exist yet. Here's how to do it:
- Check if the document exists using
.get(). - If it doesn't exist, create it with
.set(), providing an initial state object. - Wait for the creation to finish by "throwing" the promise returned by
.set().
Here's a simple example:
Why do we 'throw' the promise?
In React, 'throwing' a promise is a special way to tell React that we're waiting for some data. When we throw a promise:
- React catches it and shows a loading state (thanks to Suspense).
- When the promise resolves, React re-renders our component with the fresh data.
This ensures our component only renders when it has all the data it needs.
Putting It All Together
Here's an example of a complete React component using TeamPlay:
In this example:
- We wrap our
UserProfilecomponent withobserver(). - We use
useSub()to subscribe to user data. - We check if the user document exists and create it if it doesn't.
- We create a local
$editModesignal to manage the component's state. - We use
.get()to read values and.set()to update them.
By following these patterns, you can create React components that automatically stay in sync with your data, handle loading states, and manage document creation seamlessly.