CodeKits.devNew developer offer

React CRUD with Node.js and MySQL

A practical walkthrough of react crud with node.js and mysql, with code excerpts, failure checks and integration guidance.

By Jonathan · 5 min read

Published

React CRUD with Node.js and MySQL tutorial cover
In this article

This walkthrough covers React CRUD with Node.js and MySQL. An authenticated React and Node application with a MySQL development database. The examples assume middleware has verified the current user.

The video is an illustrated code walkthrough with AI narration. Code blocks are integration excerpts, not a complete tested application. Helper names such as stores, middleware and clients describe responsibilities you must implement in your existing project. No live server, payment provider or device execution is claimed.

Before you begin

Use a separate development environment, fictional data and test credentials. Record dependency versions and follow the official references below for your installed versions. Keep a working baseline and add one workflow at a time.

1. Specify the request contract

Define the endpoints and response shapes before wiring the interface. List, create, edit, and delete operations need predictable success and failure behaviour. Treat authorization as part of each route, not a separate user interface feature. This example scopes tasks to the signed-in user and returns not found when a record isn't available to that user. Document these choices so every client behaves consistently.

Specify the request contract
GET /api/tasks?page=1&q=report
POST /api/tasks
PATCH /api/tasks/:id
DELETE /api/tasks/:id
400 invalid input | 401 no session | 404 unavailable

2. Create the task table

Give each task a stable identifier and an owner derived from the authenticated user. The title length and status choices constrain the model. An index beginning with owner identifier supports owner-scoped lists. Add the appropriate foreign key to your users table when integrating the schema. Use migrations for changes and test against a separate database rather than resetting production records.

Create the task table
CREATE TABLE tasks (
 id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
 owner_id BIGINT UNSIGNED NOT NULL,
 title VARCHAR(120) NOT NULL,
 status ENUM("todo","doing","done") DEFAULT "todo",
 INDEX owner_list (owner_id,id)
);

3. Validate and insert

Browser validation improves feedback, but the server must enforce the same business limits. Trim the title, reject blank or excessive input, and bind values separately from the SQL. The owner comes from the session rather than the request body. Use the inserted record identifier in your response, and choose a consistent creation status so the client can distinguish success from a validation failure.

Validate and insert
const title = req.body?.title;
if (typeof title !== "string" || !title.trim() ||
    title.trim().length > 120) return res.sendStatus(400);
await db.execute(
 "INSERT INTO tasks(owner_id,title) VALUES (?,?)",
 [req.user.id, title.trim()]
);

4. Scope the update itself

Validate route identifiers and allow only the supported status values. Scope the write in the database query itself to avoid relying on a separate page permission check. Interpret your database driver's affected-row behaviour carefully: updating a value to its existing value is different from a missing record. If your response requires that distinction, use a scoped existence check or documented driver semantics.

Scope the update itself
const allowed = ["todo", "doing", "done"];
if (!allowed.includes(status)) return res.sendStatus(400);
await db.execute(
 "UPDATE tasks SET status=? WHERE id=? AND owner_id=?",
 [status, id, req.user.id]
);

5. Paginate a stable list

Validate the page and search inputs before using them. Use a fixed page size and a deterministic sort order. Parameter binding prevents input from becoming query syntax, but wildcard characters still affect search semantics, so document whether users may use them. Offset pagination is simple for a small dashboard. For large changing lists, consider a cursor based on a stable identifier.

Paginate a stable list
const limit = 20;
const offset = (page - 1) * limit;
const [rows] = await db.execute(
 "SELECT id,title,status FROM tasks WHERE owner_id=? " +
 "AND title LIKE ? ORDER BY id DESC LIMIT ? OFFSET ?",
 [req.user.id, "%" + search + "%", limit, offset]
);

6. Handle React request races

Changing a search query can create overlapping requests. Cancel obsolete requests and avoid letting an older response overwrite the latest results. Reset the page when the search changes, and show distinct loading, error, and empty states. Keep creation and editing controls disabled while their own requests are pending. A failed request should preserve the user's input rather than silently clearing it.

Handle React request races
useEffect(() => {
 const controller = new AbortController();
 loadTasks({page, query, signal: controller.signal});
 return () => controller.abort();
}, [page, query]);

7. Delete only the intended record

Deletion is a real data mutation, so confirm the user's intent and enforce ownership on the server. Prevent duplicate submissions and handle the case where another operation already removed the row. After success, refresh the authoritative list and adjust pagination if the final item on a page disappeared. Consider soft deletion or an undo workflow when the product requires recovery rather than permanent removal.

Delete only the intended record
await db.execute(
 "DELETE FROM tasks WHERE id=? AND owner_id=?",
 [id, req.user.id]
);
// React: confirm intent, submit, then reload the list.

Integration checks

Create, reload, edit, search and delete records. Test another user’s identifier, invalid status, empty title, pagination boundaries, rapid search changes and database failure.

These are verification instructions, not reported test results. The excerpts have not been executed as a complete integrated application. Review authentication, database schema, dependency versions and operational settings before deployment.

Official references

Explore CodeKits development services.