convex
Version:
Client for the Convex Cloud
175 lines (174 loc) • 5.08 kB
JavaScript
"use strict";
import {
InternalConvexClient
} from "../browser/index.js";
import React, { useContext, useMemo } from "react";
import { convexToJson } from "@convex-dev/common";
import ReactDOM from "react-dom";
import { useSubscription } from "./use_subscription.js";
if (typeof React === "undefined") {
throw new Error("Required dependency 'react' not installed");
}
if (typeof ReactDOM === "undefined") {
throw new Error("Required dependency 'react-dom' not installed");
}
function createMutation(name, sync, update = null) {
function mutation(...args) {
return sync().mutate(name, args, update);
}
mutation.withOptimisticUpdate = function withOptimisticUpdate(optimisticUpdate) {
if (update !== null) {
throw new Error(
`Already specified optimistic update for mutation ${name}`
);
}
return createMutation(name, sync, optimisticUpdate);
};
return mutation;
}
const DEFAULT_OPTIONS = {
unsavedChangesWarning: true
};
export class ConvexReactClient {
constructor(clientConfig, options) {
this.closed = false;
this.clientConfig = clientConfig;
this.listeners = /* @__PURE__ */ new Map();
this.options = { ...DEFAULT_OPTIONS, ...options };
}
get sync() {
if (this.closed) {
throw new Error("ConvexReactClient has already been closed.");
}
if (this.cachedSync) {
return this.cachedSync;
}
this.cachedSync = new InternalConvexClient(
this.clientConfig,
(updatedQueries) => this.transition(updatedQueries),
this.options
);
if (this.adminAuth) {
this.cachedSync.setAdminAuth(this.adminAuth);
}
return this.cachedSync;
}
setAuth(token) {
this.sync.setAuth(token);
}
clearAuth() {
this.sync.clearAuth();
}
setAdminAuth(token) {
this.adminAuth = token;
if (this.closed) {
throw new Error("ConvexReactClient has already been closed.");
}
if (this.cachedSync) {
this.sync.setAdminAuth(token);
}
}
watchQuery(name, ...args) {
return {
onUpdate: (callback) => {
const { queryToken, unsubscribe } = this.sync.subscribe(
name,
args
);
const currentListeners = this.listeners.get(queryToken);
if (currentListeners !== void 0) {
currentListeners.add(callback);
} else {
this.listeners.set(queryToken, /* @__PURE__ */ new Set([callback]));
}
return () => {
if (this.closed) {
return;
}
const currentListeners2 = this.listeners.get(queryToken);
currentListeners2.delete(callback);
if (currentListeners2.size == 0) {
this.listeners.delete(queryToken);
}
unsubscribe();
};
},
localQueryResult: () => {
if (this.cachedSync) {
return this.cachedSync.localQueryResult(
name,
args
);
}
return void 0;
}
};
}
mutation(name) {
return createMutation(name, () => this.sync);
}
async close() {
this.closed = true;
this.listeners = /* @__PURE__ */ new Map();
if (this.cachedSync) {
const sync = this.cachedSync;
this.cachedSync = void 0;
await sync.close();
}
}
transition(updatedQueries) {
ReactDOM.unstable_batchedUpdates(() => {
for (const queryToken of updatedQueries) {
const callbacks = this.listeners.get(queryToken);
if (callbacks) {
for (const callback of callbacks) {
callback();
}
}
}
});
}
}
const ConvexContext = React.createContext(
void 0
);
export function useConvexGeneric() {
return useContext(ConvexContext);
}
export const ConvexProvider = ({ client, children }) => {
return React.createElement(
ConvexContext.Provider,
{ value: client },
children
);
};
export function useQueryGeneric(name, ...args) {
const convex = useContext(ConvexContext);
if (convex === void 0) {
throw new Error(
"Could not find Convex client! `useQuery` must be used in the React component tree under `ConvexProvider`. Did you forget it? See https://docs.convex.dev/quick-start#set-up-convex-in-your-react-app"
);
}
const subscription = useMemo(
() => {
const watch = convex.watchQuery(name, ...args);
return {
getCurrentValue: () => watch.localQueryResult(),
subscribe: (callback) => watch.onUpdate(callback)
};
},
[name, convex, JSON.stringify(convexToJson(args))]
);
const queryResult = useSubscription(subscription);
return queryResult;
}
export function useMutationGeneric(name) {
const convex = useContext(ConvexContext);
if (convex === void 0) {
throw new Error(
"Could not find Convex client! `useMutation` must be used in the React component tree under `ConvexProvider`. Did you forget it? See https://docs.convex.dev/quick-start#set-up-convex-in-your-react-app"
);
}
return useMemo(() => convex.mutation(name), [convex, name]);
}
//# sourceMappingURL=index.js.map