In this tutorial, you will learn how you can create a simple CRUD application using React JS and PHP MySQLi.
First, we will create CRUD RESTful API using PHP and MySQLi, and then we will implement this API in React js CRUD application.
A Very Simple PHP CRUD RESTful API
1. Database Setup for PHP CRUD REST API
- Database name –
react_php_crud
- Table name –
users
Use the following SQL code to create the users
table and the structure of the users
table.
CREATE TABLE users (
id int(11) NOT NULL AUTO_INCREMENT,
user_name varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
user_email varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2. Creating PHP CRUD application
Open your Xampp htdocs folder or Wamp www directory, and create a new folder called php-react
.

After that, we have to create the follwing PHP files inside the php-react
folder.
- db_connection.php
- add-user.php
- all-users.php
- update-user.php
- delete-user.php
db_connection.php
is for making the database connection. Configure this file according to your database configuration.
<?php
$db_conn = mysqli_connect("localhost","root","","react_php_crud");
add-user.php
is for inserting new users into the database.
- POST –
/add-user.php
- Required Fields –
user_name
,user_email
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: access");
header("Access-Control-Allow-Methods: POST");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
require 'db_connection.php';
// POST DATA
$data = json_decode(file_get_contents("php://input"));
if (
isset($data->user_name)
&& isset($data->user_email)
&& !empty(trim($data->user_name))
&& !empty(trim($data->user_email))
) {
$username = mysqli_real_escape_string($db_conn, trim($data->user_name));
$useremail = mysqli_real_escape_string($db_conn, trim($data->user_email));
if (filter_var($useremail, FILTER_VALIDATE_EMAIL)) {
$insertUser = mysqli_query($db_conn, "INSERT INTO `users`(`user_name`,`user_email`) VALUES('$username','$useremail')");
if ($insertUser) {
$last_id = mysqli_insert_id($db_conn);
echo json_encode(["success" => 1, "msg" => "User Inserted.", "id" => $last_id]);
} else {
echo json_encode(["success" => 0, "msg" => "User Not Inserted!"]);
}
} else {
echo json_encode(["success" => 0, "msg" => "Invalid Email Address!"]);
}
} else {
echo json_encode(["success" => 0, "msg" => "Please fill all the required fields!"]);
}
all-users.php
is to fetch all users that exist in the database.
- GET –
/all-users.php
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: access");
header("Access-Control-Allow-Methods: GET");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
require 'db_connection.php';
$allUsers = mysqli_query($db_conn, "SELECT * FROM `users`");
if (mysqli_num_rows($allUsers) > 0) {
$all_users = mysqli_fetch_all($allUsers, MYSQLI_ASSOC);
echo json_encode(["success" => 1, "users" => $all_users]);
} else {
echo json_encode(["success" => 0]);
}
update-user.php
is for updating an existing user.
- POST –
/update-user.php
- Required Fileds –
id
,user_name
,user_email
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: access");
header("Access-Control-Allow-Methods: POST");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
require 'db_connection.php';
$data = json_decode(file_get_contents("php://input"));
if (
isset($data->id)
&& isset($data->user_name)
&& isset($data->user_email)
&& is_numeric($data->id)
&& !empty(trim($data->user_name))
&& !empty(trim($data->user_email))
) {
$username = mysqli_real_escape_string($db_conn, trim($data->user_name));
$useremail = mysqli_real_escape_string($db_conn, trim($data->user_email));
if (filter_var($useremail, FILTER_VALIDATE_EMAIL)) {
$updateUser = mysqli_query($db_conn, "UPDATE `users` SET `user_name`='$username', `user_email`='$useremail' WHERE `id`='$data->id'");
if ($updateUser) {
echo json_encode(["success" => 1, "msg" => "User Updated."]);
} else {
echo json_encode(["success" => 0, "msg" => "User Not Updated!"]);
}
} else {
echo json_encode(["success" => 0, "msg" => "Invalid Email Address!"]);
}
} else {
echo json_encode(["success" => 0, "msg" => "Please fill all the required fields!"]);
}
delete-user.php
is obviously for deleting an existing user.
- POST –
/delete-user.php
- Required Fields –
id
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: access");
header("Access-Control-Allow-Methods: POST");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
require 'db_connection.php';
$data = json_decode(file_get_contents("php://input"));
if (isset($data->id) && is_numeric($data->id)) {
$delID = $data->id;
$deleteUser = mysqli_query($db_conn, "DELETE FROM `users` WHERE `id`='$delID'");
if ($deleteUser) {
echo json_encode(["success" => 1, "msg" => "User Deleted"]);
} else {
echo json_encode(["success" => 0, "msg" => "User Not Found!"]);
}
} else {
echo json_encode(["success" => 0, "msg" => "User Not Found!"]);
}
3. All URLs of the API
POST - http://localhost/php-react/add-user.php
GET - http://localhost/php-react/all-users.php
POST - http://localhost/php-react/update-user.php
POST - http://localhost/php-react/delete-user.php
4. Creating React JS CRUD Application with the PHP API

Before we start to create this React JS CRUD application, I suggest you to read this first – Simple React js CRUD application.
First, create a new React CLI Environment called as you wish. Here I named it react-php-crud-app
.
In this project, we will use the Fetch API for making the HTTP requests, so you don’t have to install extra packages.
Now, open your react project in your favorite editor, then go to the src
folder and delete all the default files and folders because we will start from scratch.
If you are curious to know how many files you need to code to make this application, see the following image –

src/
├─ components/
│ ├─ Form.js
│ ├─ UserList.js
├─ Actions.js
├─ App.js
├─ Context.js
├─ index.css
├─ index.js
First, at the root of the src
folder create a new js file called Context.js
, here we will initialize the React JS app Context.
import React from "react";
export const AppContext = React.createContext();
export const Provider = AppContext.Provider;
After that, we will create Actions.js
in the same folder (src
). This file contains all actions such as – Insert, update, delete, fetch, enable and disable the user edit mode, etc.
import { useEffect, useState } from "react";
export const Actions = () => {
let [users, setUsers] = useState([]);
//userLength is for showing the Data Loading message.
let [userLength, setUserLength] = useState(null);
useEffect(() => {
fetch("http://localhost/php-react/all-users.php")
.then((res) => {
return res.json();
})
.then((data) => {
if (data.success) {
setUsers(data.users.reverse());
setUserLength(true);
} else {
setUserLength(0);
}
})
.catch((err) => {
console.log(err);
});
}, []);
// Inserting a new user into the database.
const insertUser = (newUser) => {
fetch("http://localhost/php-react/add-user.php", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(newUser),
})
.then((res) => {
return res.json();
})
.then((data) => {
if (data.id) {
setUsers([
{
id: data.id,
...newUser,
},
...users,
]);
setUserLength(true);
} else {
alert(data.msg);
}
})
.catch((err) => {
console.log(err);
});
};
// Enabling the edit mode for a listed user.
const editMode = (id) => {
users = users.map((user) => {
if (user.id === id) {
user.isEditing = true;
return user;
}
user.isEditing = false;
return user;
});
setUsers(users);
};
// Cance the edit mode.
const cancelEdit = (id) => {
users = users.map((user) => {
if (user.id === id) {
user.isEditing = false;
return user;
}
return user;
});
setUsers(users);
};
// Updating a user.
const updateUser = (userData) => {
fetch("http://localhost/php-react/update-user.php", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(userData),
})
.then((res) => {
return res.json();
})
.then((data) => {
if (data.success) {
users = users.map((user) => {
if (user.id === userData.id) {
user.isEditing = false;
user.user_name = userData.user_name;
user.user_email = userData.user_email;
return user;
}
return user;
});
setUsers(users);
} else {
alert(data.msg);
}
})
.catch((err) => {
console.log(err);
});
};
// Deleting a user.
const deleteUser = (theID) => {
// filter outing the user.
let userDeleted = users.filter((user) => {
return user.id !== theID;
});
fetch("http://localhost/php-react/delete-user.php", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ id: theID }),
})
.then((res) => {
return res.json();
})
.then((data) => {
if (data.success) {
setUsers(userDeleted);
if (users.length === 1) {
setUserLength(0);
}
} else {
alert(data.msg);
}
})
.catch((err) => {
console.log(err);
});
};
return {
users,
editMode,
cancelEdit,
updateUser,
insertUser,
deleteUser,
userLength,
};
};
Now, we will create our app components. So then, at the root of the src
folder, create a new folder called components, and inside this folder we need to create two components – 1) Form.js
, 2) UserList.js
.
The Form.js
is for inserting new users.
import { useState, useContext } from "react";
import { AppContext } from "../Context";
const Form = () => {
const { insertUser } = useContext(AppContext);
const [newUser, setNewUser] = useState({});
// Storing the Insert User Form Data.
const addNewUser = (e, field) => {
setNewUser({
...newUser,
[field]: e.target.value,
});
};
// Inserting a new user into the Database.
const submitUser = (e) => {
e.preventDefault();
insertUser(newUser);
e.target.reset();
};
return (
<form className="insertForm" onSubmit={submitUser}>
<h2>Insert User</h2>
<label htmlFor="_name">Name</label>
<input
type="text"
id="_name"
onChange={(e) => addNewUser(e, "user_name")}
placeholder="Enter name"
autoComplete="off"
required
/>
<label htmlFor="_email">Email</label>
<input
type="email"
id="_email"
onChange={(e) => addNewUser(e, "user_email")}
placeholder="Enter email"
autoComplete="off"
required
/>
<input type="submit" value="Insert" />
</form>
);
};
export default Form;
The UserList.js
is for displaying all the existing users.
import { useContext, useState } from "react";
import { AppContext } from "../Context";
const UserList = () => {
const {
users,
userLength,
editMode,
cancelEdit,
updateUser,
deleteUser,
} = useContext(AppContext);
// Storing users new data when they editing their info.
const [newData, setNewData] = useState({});
const saveBtn = () => {
updateUser(newData);
};
const updateNewData = (e, field) => {
setNewData({
...newData,
[field]: e.target.value,
});
};
const enableEdit = (id, user_name, user_email) => {
setNewData({ id, user_name, user_email });
editMode(id);
};
const deleteConfirm = (id) => {
if (window.confirm("Are you sure?")) {
deleteUser(id);
}
};
return !userLength ? (
<p>{userLength === null ? "Loading..." : "Please insert some users."}</p>
) : (
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{users.map(({ id, user_name, user_email, isEditing }) => {
return isEditing === true ? (
<tr key={id}>
<td>
<input
type="text"
defaultValue={user_name}
onChange={(e) => updateNewData(e, "user_name")}
/>
</td>
<td>
<input
type="email"
defaultValue={user_email}
onChange={(e) => updateNewData(e, "user_email")}
/>
</td>
<td>
<button className="btn green-btn" onClick={() => saveBtn()}>
Save
</button>
<button
className="btn default-btn"
onClick={() => cancelEdit(id)}
>
Cancel
</button>
</td>
</tr>
) : (
<tr key={id}>
<td>{user_name}</td>
<td>{user_email}</td>
<td>
<button
className="btn default-btn"
onClick={() => enableEdit(id, user_name, user_email)}
>
Edit
</button>
<button
className="btn red-btn"
onClick={() => deleteConfirm(id)}
>
Delete
</button>
</td>
</tr>
);
})}
</tbody>
</table>
);
};
export default UserList;
Again inside the src
folder, we need to create last three files – 1) App.js
, 2) index.js
, 3) index.css
.
App.js
– Where we combine all the components and providing all the actions through the context.
import { Provider } from "./Context";
import Form from "./components/Form";
import UserList from "./components/UserList";
import { Actions } from "./Actions";
function App() {
const data = Actions();
return (
<Provider value={data}>
<div className="App">
<h1>React JS + PHP CRUD Application</h1>
<div className="wrapper">
<section className="left-side">
<Form />
</section>
<section className="right-side">
<UserList />
</section>
</div>
</div>
</Provider>
);
}
export default App;
index.js
– this is the entry point of the application.
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
index.css
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: #f7f7f7;
padding: 50px;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
.App {
max-width: 900px;
margin: 0 auto;
background-color: #ffffff;
padding: 20px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
border-radius: 3px;
}
.App h1 {
background-color: #f9f9f9;
text-align: center;
padding: 20px;
margin: 0;
}
.wrapper {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
padding: 20px 0;
}
.left-side {
width: 30%;
}
.right-side {
padding-left: 20px;
width: 70%;
}
.right-side table {
width: 100%;
border-collapse: collapse;
}
.right-side table th,
.right-side table td {
border: 1px solid #cccccc;
padding: 10px;
text-align: center;
}
.right-side table td button {
margin: 5px;
}
.right-side table th {
background-color: #F9FAFB;
font-size: 20px;
padding: 15px;
}
.right-side table button {
cursor: pointer;
}
.insertForm{
background-color: #F9FAFB;
border: 1px solid #cccccc;
padding: 10px;
}
.insertForm h2 {
margin: 0 0 10px 0;
text-align: center;
}
.insertForm label {
font-weight: bold;
}
.insertForm input {
width: 100%;
padding: 10px;
font-size: 16px;
margin-bottom: 5px;
}
.insertForm [type="submit"] {
margin-top: 5px;
background: #1F2937;
color: #ffffff;
border: 1px solid rgba(0, 0, 0, 0.1);
outline: none;
border-radius: 2px;
cursor: pointer;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}
.insertForm [type="submit"]:hover {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.btn{
background: none;
border: 1px solid rgba(0, 0, 0, 0.1);
padding: 3px 5px;
outline: none;
border-radius: 2px;
}
.red-btn,
.green-btn{
background: #059669;
color: #ffffff;
}
.red-btn{
background: #DC2626;
}
.default-btn{
background: #E5E7EB;
}
.btn:hover{
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
Thank you so much
Awesome Chandan. It works fine end 2 end. Thanks for this.
Hey Vijayan,
I’m glad you liked it.
Thanks Chandan. It worked for me. Great tutorial. Really appreciate your great work and effort
Thank you Hari.
Doens’t work :/
My Log after execute: npm start.
MacBook-Air-de-Guine:react-with-php guinesoftware$ npm start
npm ERR! code ENOENT
npm ERR! syscall open
MacBook-Air-de-Guine:react-with-php guinesoftware$ npm start
npm ERR! code ENOENT
npm ERR! syscall open
npm ERR! path /Users/guinesoftware/Desktop/Estudo/package.json
npm ERR! errno -2
npm ERR! enoent ENOENT: no such file or directory, open ‘/Users/guinesoftware/Desktop/Estudo/package.json’
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent
…….
Hey John,
I think you have to install React JS properly –
Check out this – How to Setup React CLI Environment?
Thanks, I used this source
Thank you very much, sir, finally it worked. Sorry for my last comment. I was using Ampps instead of Xampps.. & That error comes.
Nicely working now.
Thank you Chandan
This is awesome
solved! Thanks for the tutorial bro..keepup the good work!
hi.
action.js is very complicated for me.
other sections are excellent.
even more complete than w3schools.about react.
You are the best, thanks 👍