React创建一个脚手架,并以类组件的方式实现一个CRUD( 增删改查 )项目
crud是指在做计算处理时的增加(Create)、读取(Read)、更新(Update)和删除(Delete)几个单词的首字母简写
npx create-react-app 项目名
- react 18.x 带来了严格模式的升级,会影响一些代码的正常逻辑,去掉严格模式,会使钩子函数执行两次
- 替换为:幽灵标签
<>>
或者
Prettier - Code formatter
去掉勾选
crud是指在做计算处理时的增加(Create)、读取(Read)、更新(Update)和删除(Delete)几个单词的首字母简写
import { Component } from "react"
export default class App extends Component {
state = {
list: [
{
id: 1,
name: "黄昏",
describe: "间谍过家家主角之一",
},
{
id: 2,
name: "阿尼亚",
describe: "间谍过家家主角之一",
},
{
id: 3,
name: "随机人物",
describe: "无描述",
},
{
id: 4,
name: "随机人物1",
describe: "无描述",
},
{
id: 5,
name: "随机人物2",
describe: "无描述",
},
],
showDialog: false,
// 定义受控数据
formData: {
name: "",
describe: "",
},
}
showMask() {
this.setState({
showDialog: true,
})
}
hideMask() {
this.setState({
showDialog: false,
formData: { name: "", describe: "" },
})
}
delRole(id) {
if (window.confirm("确定要删除该数据吗") && id) {
const { list } = this.state
this.setState({
list: list.filter((item) => item.id !== id), // 应该是已经删除过后的数据
})
}
}
updateName(event) {
this.setState({
formData: {
...this.state.formData, //为了不丢弃原来的字段
name: event.target.value,
},
})
}
updateDescribe(event) {
this.setState({
formData: {
...this.state.formData, //为了不丢弃原来的字段
describe: event.target.value,
},
})
}
btnOk() {
const { formData, list } = this.state
if (formData.name && formData.describe) {
// 区分编辑还是新增
if (formData.id) {
const index = list.findIndex((item) => item.id === formData.id)
list.splice(index, 1, formData) // 已经对list进行了修改
this.setState({
list,
formData: { name: "", describe: "" },
})
} else {
this.setState({
list: [{ ...formData, id: ~~(Math.random() * 10000) }, ...list],
formData: { name: "", describe: "" },
})
}
// setState不论设置多少次 都会汇成一次的更新 统一渲染
this.hideMask()
} else {
alert("角色和描述不能为空")
}
}
// 编辑方法
editRole(id) {
if (id) {
const { list } = this.state
this.setState({
formData: list.find((item) => item.id === id),
})
this.showMask()
}
}
render() {
const { list, showDialog, formData } = this.state
return (
<div>
<button onClick={this.showMask.bind(this)}>添加数据</button>
<table border={1}>
<thead>
<tr>
<th>id</th>
<th>名称</th>
<th>描述</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{list.map((item) => (
<tr key={item.id}>
<td>{item.id}</td>
<td>{item.name}</td>
<td>{item.describe}</td>
<td>
<div className="edit-area">
<button onClick={this.editRole.bind(this, item.id)}>
编辑
</button>
<button onClick={this.delRole.bind(this, item.id)}>
删除
</button>
</div>
</td>
</tr>
))}
</tbody>
</table>
{showDialog && (
<div className="lg-dialog">
{/* 遮罩层 */}
<div className="mask"></div>
{/* 真正显示的区域 */}
<div className="wrapper">
<div className="title">
<h3>新增角色</h3>
<span onClick={this.hideMask.bind(this)}>X</span>
</div>
<p>
<label htmlFor="">角色名称</label>
<input
type="text"
value={formData.name}
onChange={this.updateName.bind(this)}
/>
</p>
<p>
<label htmlFor="">角色描述</label>
<textarea
name=""
id=""
cols="30"
rows="5"
value={formData.describe}
onChange={this.updateDescribe.bind(this)}
></textarea>
</p>
<div className="edit-area">
<button onClick={this.btnOk.bind(this)}>确定</button>
<button onClick={this.hideMask.bind(this)}>取消</button>
</div>
</div>
</div>
)}
</div>
)
}
}
table {
width: 100%
}
td,th {
text-align: center;
height: 40px;
line-height: 40px;
}
th {
background-color: rgb(215, 188, 245);
}
.lg-dialog {
width: 100%;
height: 100vh;
position: fixed;
top: 0;
left:0;
animation: mintoMax 0.2s
}
.lg-dialog .mask {
background-color: rgba(0, 0, 0, 0.4);
width: 100%;
height: 100%;
}
.lg-dialog .wrapper {
background: #fff;
width: 400px;
height: 280px ;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.lg-dialog .wrapper h3 {
text-align: center;
}
.lg-dialog .wrapper .title span{
float: right;
position: absolute;
top: 8px;
right: 8px;
font-size:30px;
cursor: pointer;
user-select: none;
}
.edit-area {
width: 180px;
display: flex;
justify-content: space-around;
}
@keyframes mintoMax {
0% {
width: 0;
height: 0;
}
100% {
width: 100%;
height: 100%;
}
}