学习如何使用 API 和 hooks 创建具有删除功能的 React JS 表格
本文中,我将使用 REST API(JSON 占位符)和模拟数据,而不是静态 JS 对象。实际应用都是使用 API 的。
如果你想了解基于类的方法,请阅读这篇文章。
我们开始吧
钩子就像函数一样。我们对它的称呼与对函数的称呼相同。
useState()
useState接受一个参数,该参数包含属性的初始值state以及return两个值:属性的当前值和更新属性的方法state。
宣布州
const [employees, setEmployees] = useState([])
它与
const array = useState([])
const employees = array[0]
const setEmployees = array[1]
我们使用数组解构,用一行代码就写完了。
我们将 employees 定义为一个空数组,一旦我们到达该位置API,状态就会改变,并将所有API数据放入 employees 数组中。
获取数据函数
const getData = async () => {
let url = 'https://jsonplaceholder.typicode.com/users'
const response = await axios.get(url)
console.log('response', response)
setEmployees(response.data)
}
我们正在使用axiosHTTP 请求。
我们需要axios通过终端下载。
npm i axios
我们编写这个getData函数async是因为从 API 获取数据需要一些时间。所以我们规定,wait在数据加载完毕之前,先将其保存到response一个变量中。
在之前的文章中,我们调用了 api componentDidMount,但useEffecthook 已经取代了它componentDidMount,useEffect更容易阅读和编写。
useEffect(() => {
getData()
}, []) // don't forget this empty bracket it indicates the function will only run once when the component will load initially
表格标题
const renderHeader = () => {
let headerElement = ['id', 'name', 'email', 'phone', 'operation']
return headerElement.map((key, index) => {
return <th key={index}>{key.toUpperCase()}</th>
})
}
首先,我们需要确定表格需要多少列,然后将这些值定义在一个数组中。在本例中,我们需要 5 列,现在我们将遍历这些值并输出结果。th
Operation是用于编辑和删除功能的。
桌体
const renderBody = () => {
return employees && employees.map(({ id, name, email, phone }) => {
return (
<tr key={id}>
<td>{id}</td>
<td>{name}</td>
<td>{email}</td>
<td>{phone}</td>
<td className='opration'>
<button onClick={() => removeData(id)}>Delete</button>
</td>
</tr>
)
})
}
您可能已经注意到这里的逻辑employees && employees.map,我们规定employees.map只有当有员工数据时才会运行。因为从服务器加载数据需要几秒钟时间,如果我们不编写这个逻辑,我们的代码就会出错,因为员工数组最初是空的,而代码map不会在空数组上运行,它不会包含 id、name 和其他字段,因此会抛出错误。
不要把{ id, name, email, phone }我们和destructured这个对象混淆。
我们还将其id作为参数传递给了removeData该方法。
主返回函数
我们在主返回函数中调用了这两个方法。
return (
<div>
<h1 id='title'>React Table</h1>
<table id='employee'>
<thead>
<tr>{renderHeader()}</tr>
</thead>
<tbody>
{renderBody()}
</tbody>
</table>
</div>
)
}
删除功能
我们可以通过 axios 发送四种类型的请求。
- 得到
- 邮政
- 删除
- 放
对于删除操作,我们将发送删除请求。顾名思义,我们使用此方法在后端删除记录。
delete它接受url一个参数,用于指定id要删除的记录。我们将把id该参数传递给它。
有时 JSON 占位符 API 不接受删除请求,前端也不会有变化,这只是为了演示目的。
const removeData = (id) => {
let url = `https://jsonplaceholder.typicode.com/users/${id}`
axios.delete(url).then(res => {
const del = employees.filter(employee => id !== employee.id)
setEmployees(del)
console.log('res', res)
})
}
在我们的案例中,可以看到数据在前端被删除,但在后端却没有被删除。这是因为我们无法操作 JSON 占位符 API。但如果我们拥有自己的 API,并且该 API 也具备删除功能,那么一切就都能正常工作了。
为了向用户显示数据已被删除,我们使用higher-order筛选方法从前端筛选了已删除的对象。
代码重构
组织和重构代码至关重要。您可能已经注意到我们URL在两个不同的地方使用了 `<div>`,如果将来我们需要更改它该怎么办URL?难道我们要在两个地方都进行更改吗?不,我们应该在一个公共的地方定义它URL。
- 在实际项目中,我们会为此创建一个配置文件,但对于这个基于单个组件的应用程序,我将
URL在文件顶部进行定义。 - 我们还得把那些游戏机搬走,它们只是用于测试目的。
- 我们不需要初始值
div。为此,我们只需使用空括号即可。
使用 API 自定义钩子
我们可以通过将所有业务逻辑切换到自定义钩子来清理组件并使代码模块化,useApi该钩子可以在应用程序的多个地方使用。
import { useState, useEffect } from 'react'
import axios from 'axios'
export function useAPi(url) {
const [data, setData] = useState([])
useEffect(() => {
getData()
}, [])
const getData = async () => {
const response = await axios.get(url)
setData(response.data)
}
const removeData = (id) => {
axios.delete(`${url}/${id}`).then(() => {
const del = data.filter((item) => id !== item.id)
setData(del)
})
}
return { data, removeData }
}
这很简单
- 我们将把 API
url作为参数传递。 - 返回
data(这是我们的员工数据)和removeData函数。
完整代码
import React from 'react'
import { useAPi } from '../../hooks/useApi'
const URL = 'https://jsonplaceholder.typicode.com/users'
const Table = () => {
const { data, removeData } = useAPi(URL)
const renderHeader = () => {
let headerElement = ['id', 'name', 'email', 'phone', 'operation']
return headerElement.map((key, index) => {
return <th key={index}>{key.toUpperCase()}</th>
})
}
const renderBody = () => {
return (
data &&
data.map(({ id, name, email, phone }) => {
return (
<tr key={id}>
<td>{id}</td>
<td>{name}</td>
<td>{email}</td>
<td>{phone}</td>
<td className="operation">
<button className="button" onClick={() => removeData(id)}>
Delete
</button>
</td>
</tr>
)
})
)
}
return (
<>
<h1 id="title">React Table</h1>
<table id="employee">
<thead>
<tr>{renderHeader()}</tr>
</thead>
<tbody>{renderBody()}</tbody>
</table>
</>
)
}
export default Table
这样是不是简洁多了?我们的业务逻辑现在完全分离了。
造型
@import url("https://fonts.googleapis.com/css2?family=Quicksand:wght@500&display=swap");
body {
font-family: "Quicksand", sans-serif;
display: flex;
justify-content: center;
padding: 0;
color: #4d4d4d;
}
#title {
text-align: center;
}
#employee {
border-collapse: collapse;
border: 3px solid #ddd;
}
#employee td,
#employee th {
border: 1px solid #ddd;
padding: 12px;
}
#employee tr:hover {
background-color: #ddd;
}
#employee th {
padding: 10px;
text-align: center;
background-color: #4caf50;
color: white;
}
.operation {
text-align: center;
}
.button {
border: none;
outline: none;
font-size: 11px;
font-family: "Quicksand", sans-serif;
color: #f44336;
padding: 3px 10px;
border-radius: 8px;
cursor: pointer;
border: 1px solid #f44336;
background-color: transparent;
}
.button:active {
border: 1px solid blue;
}
Codepen链接
这是该项目的Codepen演示。