-
Notifications
You must be signed in to change notification settings - Fork 0
/
example.tsx
151 lines (144 loc) · 4.23 KB
/
example.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* eslint-disable jsx-a11y/anchor-is-valid */
import {
QueryClient,
QueryClientProvider,
useMutation,
useQuery,
useSuspenseQuery,
} from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { ConvexProvider, ConvexReactClient } from "convex/react";
import ReactDOM from "react-dom/client";
import {
ConvexQueryClient,
convexAction,
convexQuery,
useConvexMutation,
} from "./index.js";
import "./index.css";
import { FormEvent, useState } from "react";
import { api } from "../convex/_generated/api.js";
// Build a global convexClient wherever you would normally create a TanStack Query client.
const convexClient = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL);
const convexQueryClient = new ConvexQueryClient(convexClient);
const queryClient = new QueryClient({
defaultOptions: {
queries: {
// The queryKeyHashFn needs to be set globally: it cannot be specified
// in `setQueryData()`, so the client couldn't update the query results.
queryKeyHashFn: convexQueryClient.hashFn(),
// The queryFn is convenient to set globally to avoid needing to import
// the client everywhere.
queryFn: convexQueryClient.queryFn(),
},
},
});
convexQueryClient.connect(queryClient);
function Main() {
return (
<ConvexProvider client={convexClient}>
<QueryClientProvider client={queryClient}>
<App />
<ReactQueryDevtools initialIsOpen />
</QueryClientProvider>
</ConvexProvider>
);
}
function Weather() {
const { data, isPending, error } = useQuery(
// This query doesn't update reactively, it refetches like a normal queryFn.
convexAction(api.weather.getSFWeather, {}),
);
if (isPending || error) return <span>?</span>;
const fetchedAt = new Date(data.fetchedAt);
return (
<div className="weather">
It is {data.fahrenheit}° F in San Francisco (fetched at{" "}
{fetchedAt.toLocaleString("en-US", {
hour: "numeric",
minute: "2-digit",
second: "2-digit",
})}
).
</div>
);
}
function MessageCount() {
const [shown, setShown] = useState(true);
// This is a conditional query
const { data, isPending, error } = useQuery(
convexQuery(api.messages.count, shown ? {} : "skip"),
);
return (
<div className="message-count">
{isPending
? "? messages"
: error
? "error counting messages"
: `${data} messages`}
<span onClick={() => setShown(!shown)}>
{shown
? " (click to disable message count)"
: " (click to enable message count)"}
</span>
</div>
);
}
function App() {
const { data, error, isPending } = useQuery({
// This query updates reactively.
...convexQuery(api.messages.list, {}),
initialData: [],
});
const [newMessageText, setNewMessageText] = useState("");
const { mutate, isPending: sending } = useMutation({
mutationFn: useConvexMutation(api.messages.send),
});
const [name] = useState(() => "User " + Math.floor(Math.random() * 10000));
async function handleSendMessage(event: FormEvent) {
event.preventDefault();
if (!sending && newMessageText) {
mutate(
{ body: newMessageText, author: name },
{
onSuccess: () => setNewMessageText(""),
},
);
}
}
if (error) {
return <div>Error: {error.toString()}</div>;
}
if (isPending) {
return <div>loading...</div>;
}
return (
<main>
<h1>Convex Chat</h1>
<Weather />
<MessageCount />
<p className="badge">
<span>{name}</span>
</p>
<ul>
{data.map((message) => (
<li key={message._id}>
<span>{message.author}:</span>
<span>{message.body}</span>
<span>{new Date(message._creationTime).toLocaleTimeString()}</span>
</li>
))}
</ul>
<form onSubmit={handleSendMessage}>
<input
value={newMessageText}
onChange={(event) => setNewMessageText(event.target.value)}
placeholder="Write a message…"
/>
<input type="submit" value="Send" />
</form>
</main>
);
}
const rootElement = document.getElementById("root")!;
ReactDOM.createRoot(rootElement).render(<Main />);