Build a CRUD App in React
Create React App
We'll start by installing the project with create-react-app (CRA)
npx create-react-app react-hooks
Then run npm i
.
Now you're all set with the React.
Initial Setup
Let's start off by clearing out all the files from the boilerplate we don't need. Delete everything from the /src
folder except App.js
, index.js
, and index.css
.
In index.js
, we'll simplify it by removing the references to Service Workers.
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
ReactDOM.render(<App />, document.getElementById('root'))
And in App.js
, I'll make a simple, functional component for App
instead of a class.
App.js
import React from 'react'
const App = () => {
return (
<div className="container">
<h1>CRUD App with Hooks</h1>
<div className="flex-row">
<div className="flex-large">
<h2>Add user</h2>
</div>
<div className="flex-large">
<h2>View users</h2>
</div>
</div>
</div>
)
}
export default App
Now we have the initial setup and skeleton for the app.
Setting up the View
The first thing we'll do is make some sample data and a table to display it, for the view. Create a new directory called tables
in src
, and a file within called UserTable.js
. We'll make the skeleton for a table.
tables/UserTable.js
import React from 'react'
const UserTable = () => (
<table>
<thead>
<tr>
<th>Name</th>
<th>Username</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>Name data</td>
<td>Username data</td>
<td>
<button className="button muted-button">Edit</button>
<button className="button muted-button">Delete</button>
</td>
</tr>
</tbody>
</table>
)
export default UserTable
Now just import the file and add in the new component.
App.js
import React from 'react'
import UserTable from './tables/UserTable'
const App = () => {
return (
<div className="container">
<h1>CRUD App with Hooks</h1>
<div className="flex-row">
<div className="flex-large">
<h2>Add user</h2>
</div>
<div className="flex-large">
<h2>View users</h2>
<UserTable />
</div>
</div>
</div>
)
}
export default App
Let's bring in some random dummy data and the useState
import from React.
import React from 'react'
const UserTable = () => (
<table>
<thead>
<tr>
<th>Name</th>
<th>Username</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>Name data</td>
<td>Username data</td>
<td>
<button className="button muted-button">Edit</button>
<button className="button muted-button">Delete</button>
</td>
</tr>
</tbody>
</table>
)
export default UserTable
Now just import the file and add in the new component.
import React from 'react'
import UserTable from './tables/UserTable'
const App = () => {
return (
<div className="container">
<h1>CRUD App with Hooks</h1>
<div className="flex-row">
<div className="flex-large">
<h2>Add user</h2>
</div>
<div className="flex-large">
<h2>View users</h2>
<UserTable />
</div>
</div>
</div>
)
}
export default App
Let's bring in some random dummy data and the useState
import from React.
App.js
import React, { useState } from 'react'
import UserTable from './tables/UserTable'
const App = () => {
const usersData = [
{ id: 1, name: 'Tania', username: 'floppydiskette' },
{ id: 2, name: 'Craig', username: 'siliconeidolon' },
{ id: 3, name: 'Ben', username: 'benisphere' },
]
const [users, setUsers] = useState(usersData)
return (
<div className="container">
<h1>CRUD App with Hooks</h1>
<div className="flex-row">
<div className="flex-large">
<h2>Add user</h2>
</div>
<div className="flex-large">
<h2>View users</h2>
<UserTable users={users} />
</div>
</div>
</div>
)
}
export default App
Props works just as it did before. We'll map through the user data we sent through and display the properties for each user, or display a message if there are no users. The edit and delete buttons aren't hooked up to anything yet, so they won't do anything.
UserTable.js
import React from 'react'
const UserTable = props => (
<table>
<thead>
<tr>
<th>Name</th>
<th>Username</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{props.users.length > 0 ? (
props.users.map(user => (
<tr key={user.id}>
<td>{user.name}</td>
<td>{user.username}</td>
<td>
<button className="button muted-button">Edit</button>
<button className="button muted-button">Delete</button>
</td>
</tr>
))
) : (
<tr>
<td colSpan={3}>No users</td>
</tr>
)}
</tbody>
</table>
)
export default UserTable
Adding a new user
We're going to set up the form to add a new user.
The very first thing we can do is create the actual function that will add the new user to state. We have the setUsers
function automatically from useState
, so that's what we'll use to update the user state.
Since we're not using a real API and database, which would probably have an auto-incrementing ID, I'm going to increment the ID of the new user manually. This function will take a user
object as a parameter, and add them to the users
array of objects. The ...users
code ensures that all the previous users remain in the array.
App.js
const addUser = user => {
user.id = users.length + 1
setUsers([...users, user])
}
We're going to make a component for this, so I'll just go ahead and add the reference to the component at the top, and insert the component below the "Add user" header. We can pass the addUser()
through as a prop. Make sure not to include the parentheses when we pass it through as a reference - <AddUserForm addUser={addUser} />
, not <AddUserForm addUser={addUser()} />
.
App.js
import React, { useState } from 'react'
import UserTable from './tables/UserTable'
import AddUserForm from './forms/AddUserForm'
const App = () => {
const usersData = [
{ id: 1, name: 'Tania', username: 'floppydiskette' },
{ id: 2, name: 'Craig', username: 'siliconeidolon' },
{ id: 3, name: 'Ben', username: 'benisphere' },
]
const [users, setUsers] = useState(usersData)
const addUser = user => {
user.id = users.length + 1
setUsers([...users, user])
}
return (
<div className="container">
<h1>CRUD App with Hooks</h1>
<div className="flex-row">
<div className="flex-large">
<h2>Add user</h2>
<AddUserForm addUser={addUser} />
</div>
<div className="flex-large">
<h2>View users</h2>
<UserTable users={users} />
</div>
</div>
</div>
)
}
export default App
Now we have to create a form that you can use to add the new user. Let's create a forms
subdirectory with a file inside called AddUserForm.js
.
AddUserForm.js
import React, { useState } from 'react'
const AddUserForm = props => {
return (
<form>
<label>Name</label>
<input type="text" name="name" value="" />
<label>Username</label>
<input type="text" name="username" value="" />
<button>Add new user</button>
</form>
)
}
export default AddUserForm
Right now, the form is empty, and you cannot add any values to it due to our empty value strings, nor does the submit button do anything.
Just like before, we'll want to make some state, except this state will just be temporary, for keeping track of what's currently in the add user form.
I'm going to create an initial state with those empty values, and set the user state to the empty values. Having initial state in a variable is useful, because after we submit the form, we can return it to the initial, empty value.
Here is our full AddUserForm
component.
AddUserForm.js
import React, { useState } from 'react'
const AddUserForm = props => {
const initialFormState = { id: null, name: '', username: '' }
const [user, setUser] = useState(initialFormState)
const handleInputChange = event => {
const { name, value } = event.target
setUser({ ...user, [name]: value })
}
return (
<form
onSubmit={event => {
event.preventDefault()
if (!user.name || !user.username) return
props.addUser(user)
setUser(initialFormState)
}}
>
<label>Name</label>
<input type="text" name="name" value={user.name} onChange={handleInputChange} />
<label>Username</label>
<input type="text" name="username" value={user.username} onChange={handleInputChange} />
<button>Add new user</button>
</form>
)
}
export default AddUserForm
Deleting a user
The next one we'll tackle is deleting a user, which is the easiest functionality to take care of.
Below addUser
in App.js
, we'll create deleteUser
, which will take the ID of the user and filter them out of the user array.
const deleteUser = id => {
setUsers(users.filter(user => user.id !== id))
}
We pass that function through props to UserTable
.
<UserTable users={users} deleteUser={deleteUser} />
Now all we need to do in UserTable.js
is make sure the delete button calls that function.
<button onClick={() => props.deleteUser(user.id)} className="button muted-button">
Delete
</button>
In App.js
<div className="flex-large">
<h2>View users</h2>
<UserTable users={users} deleteUser={deleteUser} />
</div>
Comments
Post a Comment