Skip to main content

React frontend

  1. Make sure your Reboot application is running
    source ./.venv/bin/activate
    rbt dev run
  2. Set up your frontend folder
    mkdir -p frontend/web && cd frontend/web
  3. Create Vite project
    npm create vite@latest . -- --template react-ts
  4. Install @reboot-dev/reboot-react
    npm install @reboot-dev/reboot-react
  5. Add RebootClientProvider to src/main.tsx
    // ./src/main.tsx
    import { 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>
    // ...
  6. Generate React API files

    Add the following line to your existing .rbtrc file:

    generate --react=frontend/api

    In the terminal running rbt dev run you'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: [".."],
    },
    },
  7. Replace existing code in src/App.tsx
    // ./src/App.tsx
    import { 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">
    <input
    value={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;
  8. 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 App component:

    // TODO: import "./App.css";

    With:

    import "./App.css";
  9. Start your React app
    npm run dev
  10. Test your app

    View your app at the URL that npm run dev prints, by default http://localhost:5173 🎉. Try opening your app in multiple browser tabs!

  11. Add optimistic updates (optional)

    Replace this line in your App component:

    {/* 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 send method!

Next steps

Well done! You made it! Check out these links to continue your exploration: