React frontend
- Make sure your Reboot application is running
- Python
- TypeScript
source ./.venv/bin/activaterbt dev runnpx rbt dev run - Set up your frontend foldermkdir -p frontend/web && cd frontend/web
- Create Vite projectnpm create vite@latest . -- --template react-ts
- Install
@reboot-dev/reboot-reactnpm install @reboot-dev/reboot-react - Add
RebootClientProvidertosrc/main.tsx// ./src/main.tsximport { RebootClientProvider } from "@reboot-dev/reboot-react";// ...// Matching the URL that `rbt dev run` prints out.const url = "http://localhost:9991";// ...<RebootClientProvider url={url}><App /></RebootClientProvider>// ... - Generate React API files
Add the following line to your existing
.rbtrcfile:generate --react=frontend/apiIn the terminal running
rbt dev runyou'll see that the change is detected and the React code is generated.The generated code lives outside the app's root directory, so tell Vite it is allowed to serve it by adding the following to
vite.config.ts:server: {fs: {allow: [".."],},}, - Replace existing code in
src/App.tsx// ./src/App.tsximport { useState } from "react";import { useChatRoom } from "../../api/chat_room/v1/chat_room_rbt_react";// TODO: import "./App.css";const App = () => {const [message, setMessage] = useState("Hello, Reboot!");const { useMessages, send } = useChatRoom({ id: "reboot-chat-room" });const { response } = useMessages();const handleSend = async () => {if (message.trim()) {await send({ message });setMessage("");}};return (<div className="app-container"><h3 className="app-title">This is Reboot 🎉</h3><div className="messages-container">{response?.messages.map((msg, index) => (<div key={index} className="message">{msg}</div>))}{/* TODO: render pending messages optimistically. */}</div><div className="input-container"><inputvalue={message}onChange={(e) => setMessage(e.target.value)}onKeyDown={(e) => e.key === "Enter" && handleSend()}placeholder="Type your message here..."className="message-input"/><button onClick={handleSend} className="send-button">Send</button></div></div>);};export default App; - Add styling (optional)/* ./src/App.css */.app-container {max-width: 500px;margin: 50px auto;padding: 20px;border: 1px solid #ddd;border-radius: 8px;font-family: Arial, sans-serif;}.app-title {text-align: center;font-weight: normal;margin-bottom: 20px;}.messages-container {margin-bottom: 20px;max-height: 300px;overflow-y: auto;}.message {background-color: #e3f2fd;padding: 8px 12px;margin: 4px 0;border-radius: 12px;word-wrap: break-word;color: black;}.pending-message {background-color: #fff3cd;padding: 8px 12px;margin: 4px 0;border-radius: 12px;word-wrap: break-word;opacity: 0.8;}.input-container {display: flex;gap: 8px;}.message-input {padding: 10px;flex: 1;border: 1px solid #ddd;border-radius: 20px;outline: none;}.message-input:focus {border-color: #007bff;}.send-button {padding: 10px 16px;background-color: #007bff;color: white;border: none;border-radius: 20px;cursor: pointer;}.send-button:hover {background-color: #0056b3;}
Then replace this line in your
Appcomponent:// TODO: import "./App.css";With:
import "./App.css"; - Start your React appnpm run dev
- Test your app
View your app at the URL that
npm run devprints, by defaulthttp://localhost:5173🎉. Try opening your app in multiple browser tabs! - Add optimistic updates (optional)
Replace this line in your
Appcomponent:{/* TODO: render pending messages optimistically. */}With this code:
{send.pending.map(({ request: { message } }, index) => (<div key={`pending-${index}`} className="pending-message">{message} (sending...)</div>))}This will show messages immediately when you click Send, even before the backend confirms they've been processed. Try it out by making your backend sleep for a few seconds in the
sendmethod!
Next steps
Well done! You made it! Check out these links to continue your exploration:
- Add sign-in -
useSignIn()and the generateduseUser()hook, once your backend has aUsertype. - Learn advanced React usage - like error handling, or Next.js and Server Components.
- Learn about transactions - so far,
you've seen
readerandwritermethods, but Reboot's power extends totransactions. Learn abouttransactionsand all of the other method kinds here. - Join us on Discord - to ask questions and let us know what you think!