React 增删查改 快速上手

前言

我将以学生管理作为例子,使用react框架和antd样式来实现增删查改的功能

gitee项目地址: React 增删查改: 使用react完成一个简单的学生管理增删查改项目icon-default.png?t=N7T8https://gitee.com/a-kodak-duck/react-crud.git

环境准备

关于后端

如果同学不会后端的语言,可以直接使用json-server来做

json-server 增删查改 快速上手

后续我将会补充springboot和flask的增删查改快速上手(也会把vue的增删查改写一遍)

关于数据库

json-server 的数据格式如下 gender=0为男,1为女

{
  "student": [
    {
      "id": "1",
      "name": "阿松大",
      "age": 23,
      "major": "软件",
      "gender": 0
    },
    {
      "id": "2",
      "name": "撒旦",
      "age": 23,
      "major": "计算机",
      "gender": 1
    }
  ]
}

新建react项目

npx create-react-app 项目名称

npx create-react-app student-view

然后进入项目文件夹,启动项目(是的,我们不需要npm install)

PS C:\Users\Desktop> cd student-view
PS C:\Users\Desktop\student-view> npm start

出现这个页面,我们就成功了

然后我们,清理一些不相关的文件和代码,清理完后是下面这个样子

我们只需要

App.js(组件,我们直接在这个文件里写学生管理的页面,App只是个名字,你可以直接改为Student.js,改完后不要忘记也要修改在index.js对应的名字噢) 

index.js(项目入口文件)

简化后,页面长这样

react是热部署的,您不需要重启应用和手动刷新 

添加相关依赖

Antd 样式组件 Ant Design of React - Ant Design

为了让我们页面好看些,我们可以引入antd样式组件,antd相比于element而言,更支持react

npm i antd

Axios 异步请求工具 axios中文网|axios API 中文文档 | axios

axios是一个异步请求工具,比起原生的AJAX和Promise更方便,更简洁,我们将使用axios来向后端发起异步请求

npm i axios

前端样式搭建

为了解决大家时间,我直接把样式代码贴到这里

新建一个app.css文件

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}
.App {
  padding: 5px;
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
header {
  width: 100%;
  height: 8vh;
  display: flex;
  align-items: center;
}
main {
  width: 100%;
  height: 90vh;
}
/* .ant-table-body {
  min-height: 72.5vh;
} */

App.js

import { Button, Input, Table, Tag } from 'antd';
import { useState } from 'react';
import './app.css';

function App() {
  // 表格参数的控制
  const columns = [
    {
      title: '学生姓名',
      dataIndex: 'name',
      key: 'name',
    },
    {
      title: '年龄',
      dataIndex: 'age',
      key: 'age',
    },
    {
      title: '专业',
      dataIndex: 'major',
      key: 'major',
    },
    {
      title: '性别',
      key: 'gender',
      dataIndex: 'gender',
      render: (_,{ gender }) => (
        <span>{gender === 0 ? <Tag color='blue'>男</Tag>:<Tag color='orange'>女</Tag>}</span>
      ),
    },
    {
      title: '操作',
      key: 'action',
      render: (record)=>(
        <span>
          <Button style={{'backgroundColor':'orange','color':'white', 'marginRight':'5px'}}>编辑</Button>
          <Button type='primary' danger>删除</Button>
        </span>
      )
    },
  ];
  //假数据
  const data = [
    {
      id: '1',
      name: '张三',
      age: 32,
      major: '计算机',
      gender:0
    },
    {
      id: '2',
      name: '李四',
      age: 42,
      major: '软件工程',
      gender:0
    },
    {
      id: '3',
      name: '王五',
      age: 32,
      major: 'Sydney No. 1 Lake Park',
      gender:1
    },
  ];
  //批量选中行的id
  const [selectedRowKeys, setSelectedRowKeys] = useState([]);
  //批量选中事件
  const rowSelection = {
    onChange: (newSelectedRowKeys) => {
      setSelectedRowKeys(newSelectedRowKeys);
    }
  };
  return (
    <div className="App">
      {/* 头部:操作栏 */}
      <header>
        <Button type="primary" danger disabled={selectedRowKeys.length === 0}>批量删除</Button>
        <Button type='primary' style={{'backgroundColor':'green','margin':'0 5px'}}>新增学生</Button>
        <Input.Search style={{'width':'200px'}} allowClear  placeholder="搜索学生姓名" enterButton />
      </header>
      {/* 主体:学生表格 */}
      <main>
        <Table 
        rowKey={(record)=>record.id} 
        pagination={{
          current: 1,
          pageSize: 10,
          total: 100
        }}
        rowSelection={rowSelection}  
        columns={columns} 
        dataSource={data} 
        scroll={{y:1000}}/>
      </main>
    </div>
  );
}

export default App;

 最终长这个样子(样式大家凑合着看哈,按需改)

统一封装请求接口

我们可以先把所有的api接口封装到一个文件里面,再在页面中调用方法,这样能方便管理

新建一个api.js

import axios from "axios";

const Server_Url = 'http://localhost:8080/student'

/**
 * 获取-学生列表信息
 * @param {*} params 带条件的分页查询参数
 * @returns 学生列表
 */
export const getStudentList = (params)=>axios.get(Server_Url,{
  params
})

/**
 * 获取-满足查询条件的所有学生列表信息(主要是为了分页查询的count数据)
 * @returns 学生列表
 */
export const getTotalStudent = (name)=>axios.get(Server_Url,name)

/**
 * 获取-学生个人信息
 * @param {*} id 学生id 
 * @returns 学生个人信息
 */
export const getStudent = (id) => axios.get(Server_Url+'/'+id)

/**
 * 删除-学生
 * @param {*} id 学生id
 * @returns 
 */
export const deleteStudent = (id) => axios.delete(Server_Url+'/'+id)

/**
 * 更新-学生信息
 * @param {*} id 学生id
 * @param {*} data 更新的学生信息
 * @returns 更新后的学生信息
 */
export const updateStudent = (id,data) => axios.put(Server_Url+'/'+id,data)

/**
 * 新建-学生信息
 * @param {*} data 学生信息
 * @returns 
 */
export const createStudent = (data) => axios.post(Server_Url,data)

好了,启动后端接口,我们正式开始

增删查改

带条件分页查询

首先,我们先在页面上获取数据

  //获取学生列表
  useEffect(()=>{
    async function handleGetStudentList(){
      const res = await getStudentList()
      console.log(res.data)
    }
    handleGetStudentList()
  },[])

获取成功

我们再来完善这块的代码,将请求参数携带进去,并把相应的数据绑定到页面上,还有分页器的分页动作绑定

//带条件的分页搜索参数
  const [params, setParams] = useState({
    _page:1,//第一页
    _per_page:2,//每页展示2页数据(json-server超过0.17就需要使用_per_page替换_limit)
    name:''//学生姓名
  })
  //获取学生列表
  const [studentList, setStudentList] = useState([])
  const [total, setTotal] = useState(0)
  useEffect(()=>{
    async function handleGetStudentList(){
      const res = await getStudentList(params)
      setTotal(res.data.items)
      setStudentList(res.data.data)
    }
    handleGetStudentList()
  },[params])//监听搜索参数的变化,如果变化了,就重新获取数据
  //分页器发生变化
  function handlePaginationChange(newPageNum,newPageSize){
    setParams({
      ...params,
      _page:newPageNum,
      _per_page:newPageSize
    })
  }
  return (
    <div className="App">
      {/* 头部:操作栏 */}
      <header>
        <Button type="primary" danger disabled={selectedRowKeys.length === 0}>批量删除</Button>
        <Button type='primary' style={{'backgroundColor':'green','margin':'0 5px'}}>新增学生</Button>
        <Input.Search 
          value={params.name}
          onChange={(e)=>setParams({...params, name:e.target.value})}
          style={{'width':'200px'}} 
          allowClear  
          placeholder="搜索学生姓名" 
          enterButton />
      </header>
      {/* 主体:学生表格 */}
      <main>
        <Table 
        rowKey={(record)=>record.id} 
        pagination={{
          current: params._page,
          pageSize: params._per_page,
          total:total,
          onChange:handlePaginationChange
        }}
        rowSelection={rowSelection}  
        columns={columns} 
        dataSource={studentList} 
        scroll={{y:1000}}/>
      </main>
    </div>
  );

注意:

name:'' //此处需要输入完整的学生姓名,很遗憾,即使我使用了name_like也无法实现模糊查询,因此只能特定查询完整的学生姓名了,如果有知道了,请告诉我一下,谢谢

添加学生

我们来新建一个弹窗,里面存一个学生数据表单

//控制窗口打开的函数
  const [isModalOpen, setIsModalOpen] = useState(false)
  const [form] = Form.useForm();
  //打开新增窗口
  const handleOpenAddModal = ()=>{
    form.resetFields();//每次打开新增窗口时都要清空数据
    setIsModalOpen(true)
  }
  // 关闭弹窗
  const handleCancel = ()=>{
    setIsModalOpen(false)
  }
  // 提交表单
  const onFinish = async (val)=>{
    await createStudent(val)
    setParams({
      ...params
    })//重新获取数据
    message.success('新增学生成功')
    setIsModalOpen(false)
  }



{/* 新建/更新学生 */}
      <Modal 
        title="新增学生" 
        open={isModalOpen} 
        onCancel={handleCancel} 
        footer={[]}// 设置footer为空,去掉 取消 确定默认按钮
        >
        <Form
          form={form}//使用 Form 组件的 form 属性将 form 对象与 Form 组件进行关联
          name="basic"
          labelCol={{ span: 8 }}
          wrapperCol={{ span: 16 }}
          style={{ maxWidth: 400 }}
          initialValues={{ remember: true }}
          onFinish={onFinish}
          autoComplete="off"
        >
          <Form.Item
            label="学生姓名"
            name="name"
            rules={[{ required: true, message: '请输入学生姓名' }]}
          >
            <Input />
          </Form.Item>
          <Form.Item
            label="年龄"
            name="age"
            rules={[{ required: true, message: '请输入年龄' }]}
          >
            <InputNumber  />
          </Form.Item>
          <Form.Item
            label="专业"
            name="major"
            rules={[{ required: true, message: '请输入专业' }]}
          >
            <Input />
          </Form.Item>
          <Form.Item label="性别" name='gender' rules={[{required:true,message:'请选择性别'}]}>
            <Radio.Group>
              <Radio value={0}> 男 </Radio>
              <Radio value={1}> 女 </Radio>
            </Radio.Group>
          </Form.Item>
          <Form.Item wrapperCol={{ offset: 8, span: 16 }}>
            <Button type="primary" htmlType="submit">
              确认提交
            </Button>
          </Form.Item>
        </Form>
      </Modal>

效果图

更新学生

我们与新增学生同一个表单

首先设置操作列 record 是当前行的数据对象

    {
      title: '操作',
      key: 'action',
      render: (record)=>(
        <span>
          <Button 
            style={{'backgroundColor':'orange','color':'white', 'marginRight':'5px'}} 
            onClick={()=>handleOpenUpdateModal(record)}>
              编辑
          </Button>
          <Button type='primary' danger>删除</Button>
        </span>
      )
    },

然后在打开弹窗后,编辑更新表单数据

 //用一个变量来记录,当前是否是更新状态
  const [isUpdate,setIsUpdate] = useState(false)
  //打开编辑弹窗
  const handleOpenUpdateModal = (value) => {
    form.setFieldsValue(value)//将当前行的数据赋值给表单
    setIsUpdate(true)
    setIsModalOpen(true)
  }
  //编辑学生
  const handleUpdateStudent = async (value) => {
    await updateStudent(value.id,value)
    message.success('编辑成功')
    setIsModalOpen(false)
    setParams({
      ...params
    })
  }

 优化弹窗和表单,注意我添加了一个隐藏Form.Item来存储学生id

{/* 新建/更新学生 */}
      <Modal 
        title={isUpdate?'编辑学生':'新增学生'}
        open={isModalOpen} 
        onCancel={handleCancel} 
        footer={[]}// 设置footer为空,去掉 取消 确定默认按钮
        >
        <Form
          form={form}//使用 Form 组件的 form 属性将 form 对象与 Form 组件进行关联
          name="basic"
          labelCol={{ span: 8 }}
          wrapperCol={{ span: 16 }}
          style={{ maxWidth: 400 }}
          initialValues={{ remember: true }}
          onFinish={isUpdate? handleUpdateStudent : handleCreateStudent}
          autoComplete="off"
        >
          <Form.Item name='id' hidden>
            <Input/>
          </Form.Item>
          <Form.Item
            label="学生姓名"
            name="name"
            rules={[{ required: true, message: '请输入学生姓名' }]}
          >
            <Input />
          </Form.Item>
          <Form.Item
            label="年龄"
            name="age"
            rules={[{ required: true, message: '请输入年龄' }]}
          >
            <InputNumber  />
          </Form.Item>
          <Form.Item
            label="专业"
            name="major"
            rules={[{ required: true, message: '请输入专业' }]}
          >
            <Input />
          </Form.Item>
          <Form.Item label="性别" name='gender' rules={[{required:true,message:'请选择性别'}]}>
            <Radio.Group>
              <Radio value={0}> 男 </Radio>
              <Radio value={1}> 女 </Radio>
            </Radio.Group>
          </Form.Item>
          <Form.Item wrapperCol={{ offset: 8, span: 16 }}>
            <Button type="primary" htmlType="submit">
              确认提交
            </Button>
          </Form.Item>
        </Form>
      </Modal>

效果图

删除学生

单个删除

首先,为了避免用户手滑误删,我们用个popover包裹一下删除按钮,进行二次确认

{
      title: '操作',
      key: 'action',
      render: (record)=>(
        <span>
          <Button 
            style={{'backgroundColor':'orange','color':'white', 'marginRight':'5px'}} 
            onClick={()=>handleOpenUpdateModal(record)}>
              编辑
          </Button>
          <Popover 
            title='警告!您确定要删除吗?' 
            content={
                <Button
                  onClick={() => handleDeleteStudent(record.id)}
                  type='primary' danger
                  >
                  确定
                </Button>
              }>
            <Button type='primary' danger>删除</Button>
          </Popover>
        </span>
      )
    },

然后就可以编写删除的逻辑了

  //删除学生
  const handleDeleteStudent = async (id) => {
    await deleteStudent(id)
    message.success('删除成功')
    setParams({
      ...params
    })
  }

效果如图

批量删除 

还记得最开始写的批量选中事件吗,我们可以直接这些得到的id数组使用fori遍历循环,每个都调用一次删除方法就可以了

首先我们还是需要对批量删除按钮进行二次确认警告的设置

<Popover 
   trigger="click" //注意要改为点击模式,默认为hover,但是如果是hover的话,批量按钮即使是disable也会弹出来确认框
   title='警告!您确定要删除这些学生吗?' 
   content={
     <Button
     onClick={handleBatchDelete}
     type='primary' danger
      >
      确定
      </Button>
   }>
     <Button type="primary" danger disabled={selectedRowKeys.length === 0} >批量删除</Button>
</Popover>

 然后就是逻辑处理

  //批量删除
  const handleBatchDelete = ()=>{
    for(let i = 0; i < selectedRowKeys.length; i++){
      deleteStudent(selectedRowKeys[i])
    }
    setParams({
      ...params
    })
  }

效果图

完结

以上所有的增删查改就做完了

gitee代码也做了同步更新

React 增删查改: 使用react完成一个简单的学生管理增删查改项目icon-default.png?t=N7T8https://gitee.com/a-kodak-duck/react-crud.git

React 是一个流行的 JavaScript 库,用于构建用户界面。虽然 React 本身只关注 UI 的展示,但它可以与其他库或框架搭配使用来实现增删查改的功能。 首先是增加数据的功能。在 React 中,我们可以使用状态(state)来存储和管理数据。通过创建一个初始状态(initial state),我们可以使用 this.setState() 方法来更新状态。例如,当用户点击“添加”按钮时,我们可以通过在状态中添加一个新的数据项来实现数据的增加。 其次是删除数据的功能。同样,我们可以使用状态来存储数据,并通过 this.setState() 方法来更新状态。当用户点击“删除”按钮时,我们可以通过过滤状态中的数据项来实现数据的删除。可以使用 Array.filter() 方法来实现过滤。 第三是查找数据的功能。在 React 中,我们可以使用状态来存储数据,并通过 this.setState() 方法来更新状态。当用户输入相应的查询条件时,我们可以使用 Array.filter() 方法来过滤状态中的数据项,并根据查询条件来显示相应的数据。 最后是修改数据的功能。与增加和删除数据类似,我们可以使用状态来存储数据,并通过 this.setState() 方法来更新状态。当用户点击“编辑”按钮时,我们可以根据相应的索引或唯一标识符找到需要修改的数据项,并将其更新为用户输入的新数据。 总之,React 提供了一种简单而强大的方式来实现增删查改功能。通过利用状态管理数据并使用相应的方法来更新状态,我们可以轻松地实现这些功能,从而提供一个交互式的用户界面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值