How to Build a React Todo App with Bazaar
In this tutorial, you will build a simple Todo application using React and Bazaar. This guide will walk you through setting up a new React project, integrating Bazaar for backend services, and deploying your application to Netlify. By the end of this tutorial, you will have a fully functional Todo app with features to add, display, mark as complete, and delete tasks.
Prerequisites
To complete this tutorial, you will need:
- A basic understanding of React.
- Node.js installed on your machine.
- Git installed on your machine.
- A GitHub account for code repository hosting.
- (Optional) A Netlify account for deploying your app.
Step 1 — Scaffolding a New React Project
In this step, you will create a new React project with TypeScript using the official Vite project scaffolding tool, create-vite
.
Open up your terminal and ensure your current working directory is where you intend to create a project. Then, Run the following command:
That command will install and execute create-vite
, creating your React project in a folder named bazaar-react-todo
. The option , react-ts
, is the React + TypeScript template preset.
Next, navigate to your project directory, install dependencies, and start the development server:
Open the default URL http://localhost:5173/
in your browser to see the starter React project.
In the next step, you’ll prepare your project by cleaning up unnecessary scaffolded files and adding custom styles.
Step 2 — Preparing the Project
In this step, you will clean up the scaffolded React project by removing unnecessary files and adding custom styles.
-
First, delete the following files and folders:
src/App.css
src/assets/react.svg
-
Replace the contents of
src/assets/index.css
with: -
Finally, replace the contents of
src/App.tsx
with the following:
Check your app in the browser to see the text Todo.
With the project cleaned up, you are ready to integrate Bazaar for authentication and realtime data storage.
Step 3 — Running the Mock Server
In this step, you will use the Bazaar mock server to develop your app locally. The mock server simulates the Bazaar backend, allowing you to test and build your application in a local environment.
In a new terminal window, run the following command to start the mock server:
This command assumes the Vite dev server is running on the default port 5173
. Update accordingly if you’re running on a different port.
Install the @bzr/bazaar-mock
NPM package if prompted.
You should see output similar to this:
Now that the mock server is running, you’ll initialize a Bazaar client.
Step 4 — Initializing a Bazaar Client
In this step, you will install and initialize the Bazaar client to manage backend services for your Todo app.
First, install the Bazaar library:
Next, initialize the Bazaar client at the top of src/App.tsx
:
In this code, you set the following BazaarApp
options:
appId
: Checks for aVITE_APP_ID
environment variable and, if not present, usestest
, the Bazaar mock server default.loginRedirectUri
: Checks for aVITE_URL
environment variable and, if not present, useswindow.location.href
as the default, e.g.http://localhost:5173/
.onApiConnectError
: If a connection error occurs, logs out the user.
Open the app in your browser and check the developer console. You’ll see the following:
With the Bazaar client initialized you can now add authentication to your app.
Step 5 — Adding User Authentication
In this step, you’ll add user authentication to your app using Bazaar’s OAuth2-based authentication system.
First, add log in and log out buttons to your template:
When a user clicks the log in button, a pop-up window opens, prompting them to create a Bazaar account or log in if they already have one. Once the account is created, the user is prompted to authorize your Todo app.
Create a test account by entering any email address, using the code 1234
and choosing any handle and name. Then, authorize the app. The pop-up will close. Refresh the page, and in your developer console you’ll see the following:
Next, refactor the code so the login status updates immediately after a successful login, not just on page load.
In these changes, you wrap the login code in useEffect
with an empty dependency array so the code is executed only on the component’s initial render. The code needs to be in the component function because you will use reactive state in the doLoginActions
function in the next step.
Log out and log back in, and you’ll see is logged in: true
in your console after the pop-up closes without needing a page refresh.
You have now added user authentication to your app. Next, you will conditionally display content based on the user’s login status.
Step 6 — Displaying Logged-in Content
In this step, you will conditionally display content based on the user’s login status.
First, make the following changes:
In these changes, you create a state variable for the login status and set its value to true
when a user logs in. Next, you update the template to display log in and log out buttons conditionally.
Next, you’ll add the functionality to create todos.
Step 7 — Adding a Todo
In this step, you’ll implement the feature to create todos.
Make the following changes to your script:
In this code, you define a Todo
type and create two state variables, one for the new todo text and another for holding the list of todos.
The bzr.collection
method creates an object to interact with a database collection. Learn more in the collections docs.
The onSubmit
function adds a new todo to the todos
collection with todosCollection.insertOne
(collections are created lazily) and adds the todo to your app’s local state with the ID generated by the database after insertion.
Next, add the form to your template after the log out button:
In these changes, you hook up the onSubmit
handler to the form submit event and bind the todoText
state variable you just created to the input. There are now multiple logged-in elements, which get wrapped in a fragment (<></>
).
You have now implemented the functionality to add new todos, but they still need to be displayed.
In the next step, you will display these todos in your app.
Step 8 — Displaying Todos
In this step, you will fetch and display todos from the collection.
First, update the doLoginActions
function to fetch todos:
In this code, todosCollection.getAll()
fetches all the todos from the collection, and the results are stored in the todos
state variable.
Next, update the template to display the todos under the form:
Add a few more todos in your browser and notice they get added to the bottom of your list. Usually you want the newest todos to appear first. To do that, you’ll reverse the fetched todos.
Start by adding reversedTodos
, which derives its state from todos
:
The spread operator (...
) creates a new array, as the reverse
method mutates an array.
Then, in your template, replace todos
with the new reversedTodos
state variable to list the todos:
You have now successfully displayed the todos fetched from the collection. In the next step, you will add realtime syncing to keep the todos updated across different devices.
Step 9 — Adding Realtime Syncing
In this step, you will enable realtime updates for your todos so that changes are reflected instantly across different devices.
Add the following to the doLoginActions
function:
In this code, todosCollection.subscribeAll
subscribes to all changes in the todos
collection. You pass a subscribe listener as the second subscribeAll
argument with a function to handle onAdd
events. When an onAdd
event is triggered, you update your local state.
Learn about subscribe listeners.
With the onAdd
handler in place, there’s no need to add a todo to your local state when the form is submitted. Replace the submit event listener with the following:
The main line removed is setTodos([...todos, { id, ...unpersistedTodo }]);
. The function no longer needs to be async as you don’t need to wait for the ID from the database and is updated accordingly.
To test the realtime updates, open your app in a private window while keeping the original window open. When you make changes in one window, they will appear in the other in realtime.
Realtime syncing is enabled, but it only handles add todo events. In the next step, you will implement the functionality to toggle the completion status of todos and update your subscribe listener with an onChange
handler.
Step 10 — Toggling Todo Completion
In this step, you’ll implement functionality to toggle the completion status of todos.
First, add an onChange
handler to your subscribe listener:
The onChange
handler updates the corresponding todo in your local state. Note that the first parameter in the onChange
handler is newDoc
, which you don’t need. An underscore is used as the parameter name to indicate the variable is unused and to avoid a React build error.
Next, update your template:
In these changes, you add a strikethrough
class to a todo when it’s complete. The strikethrough
style is already in index.css
.
And add the toggleTodoCompletion
click event handler below onSubmit
:
That function updates the completed
value for a todo, setting it to the opposite of its current state.
You can now mark todos as completed or incomplete. In the next step, you will add the functionality to delete todos.
Step 11 — Deleting a Todo
In this step, you will implement the functionality to delete todos.
First, add an onDelete
handler to your subscribe listener:
The onDelete
handler deletes the corresponding todo from your local state.
Next, add a delete button to your template:
And add the toggleTodoCompletion
click event handler below deleteTodo
:
Now you can delete todos.
Show the Completed App.tsx
File
With that, your todo app is complete and ready to deploy.
Step 12 — Deploying to Netlify
In this step, you will deploy your React Todo app to Netlify. You can deploy a Bazaar-powered app anywhere static sites can be hosted. Netlify provides a frictionless deployment process and free static site hosting for public GitHub repos.
First, initialize a Git repository and push your code to GitHub:
Go to GitHub and create a public repo named bazaar-react-todo
.
Next, go to Netlify, create an account if necessary, and click Add new site. Select Import an existing project and choose GitHub. Select your repository bazaar-react-todo
. If you can’t find your repo, click Configure the Netlify app on GitHub to grant access.
Configure the site settings and build settings as follows:
- Site name: e.g.
bazaar-react-todo
- Branch to deploy: e.g.
main
- Build command:
npm run build
(default) - Publish directory:
dist
(default)
Add environment variables VITE_URL
and VITE_APP_ID
. For VITE_URL
, use your app’s Netlify URL (e.g., https://bazaar-react-todo.netlify.app
).
To get your Bazaar app ID, open cloud.bzr.dev and create a free account. Click on the user icon at the top right, then click Developers. Next, click Create App.
Give your app a name. I’m using React Todo. Set your APP URL, which should be the same as your app’s Netlify URL, e.g. https://bazaar-react-todo.netlify.app
. Finally, click Create, then copy your app ID. It will look something like 01907291-d4e5-79d5-a312-ba20260c9b98
.
Return to Netlify and paste in your app ID as the VITE_APP_ID
value, and click Deploy. You’ll see a notice, Site deploy in progress. The process will take a few minutes, after which your todo app will be deployed!
Conclusion
In this tutorial, you built and deployed a Todo app using React and Bazaar. You set up a new React project, integrated Bazaar for backend services, implemented user authentication, added and displayed todos, enabled realtime syncing, and deployed your app to Netlify.
Check the Bazaar documentation for more features and capabilities.