You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ReactJs编辑表单中加载填充已有数据库用户记录

问题描述

我需要一个可更新用户数据(包含code、article、price、vat、status、companyid字段)的表单,要求打开编辑弹窗时,通过API获取该用户的对应数据并自动填充到输入框中,方便进行修改操作。以下是我目前的代码实现:

原组件代码

import { getUsers, editUser } from '../Service/api'
import { useEffect } from 'react'

const DialogEditUser = (data) => {
  const [RowData, SetRowData] = useState([])
  const [ViewEdit, setEditShow] = useState(false)
  const [id, setId] = useState('')
  const [code, setCode] = useState('')
  const [article, setArticle] = useState('')
  const user = { id, code, article }

  const normalize = (v) => ({
    code: String(v.code),
    article: String(v.article),
  })

  const handleEditShow = () => {
    setEditShow(true)
  }
  const handleEditClose = () => {
    setEditShow(false)
  }

  const handleEdit = () => {
    editUser(data.props, normalize(user))
  }

  useEffect(() => {
    getUsers()
  }, [])

  return (
    <>
      <CButton
        style={{
          marginRight: '10px',
          color: 'info',
          border: 'none',
          boxShadow: `2px 2px 9px -3px rgba(0,0,0,0.6)`,
        }}
        onClick={() => handleEditShow(SetRowData(data), setId(data.id))}
      >
        Edit
      </CButton>
      <CModal
        visible={ViewEdit}
        onClose={handleEditClose}
        backdrop={'static'}
        keyboard={false}
        portal={false}
      >
        <CModalHeader>
          <CModalTitle>Edit User:</CModalTitle>
        </CModalHeader>
        <CModalBody>
          <CForm>
            <CFormInput
              type="text"
              id="exampleFormControlInput1"
              label="Code :"
              placeholder="Enter Code"
              text=" "
              aria-describedby="exampleFormControlInputHelpInline"
              name="code"
              onChange={(e) => setCode(e.target.value)}
              defaultValue={RowData.code}
            />
            <CFormInput
              type="text"
              id="exampleFormControlInput2"
              label="Article :"
              placeholder="Enter Article"
              text=" "
              aria-describedby="exampleFormControlInputHelpInline"
              name="article"
              onChange={(e) => setArticle(e.target.value)}
              defaultValue={RowData.article}
            />
        <CModalFooter>
          <CButton color="secondary" onClick={() => setEditShow(false)}>
            Cancel
          </CButton>
          <CButton
            color="primary"
            onClick={() => {
              handleEdit()
              setEditShow(false)
            }}
          >
            Update
          </CButton>
        </CModalFooter>
      </CModal>
    </>
  )
}

export default DialogEditUser

原API代码(src/Service/api.js)

//...
export const getUsers = async (id) => {
  id = id || ''
  try {
    return await axios.get(`${baseURL}`, config)
  } catch (error) {
    console.log('Error while calling getUsers api ', error)
  }
}
//...

修正方案

1. 修复API函数

修改getUsers,让它根据传入的id获取单个用户数据:

// src/Service/api.js
export const getUsers = async (id) => {
  try {
    // 传入id则获取单个用户,否则获取用户列表
    const url = id ? `${baseURL}/${id}` : baseURL;
    const response = await axios.get(url, config);
    return response.data; // 直接返回响应体数据,方便组件使用
  } catch (error) {
    console.log('Error while calling getUsers api ', error);
    throw error; // 抛出错误,让组件可以处理异常
  }
}

2. 修正组件逻辑

调整props接收、状态管理、弹窗打开时的数据获取逻辑:

import { getUsers, editUser } from '../Service/api';
import { useState, useEffect } from 'react';

// 解构接收父组件传入的用户数据
const DialogEditUser = ({ user }) => {
  const [isEditOpen, setIsEditOpen] = useState(false);
  // 用单个对象统一管理所有表单字段状态
  const [formData, setFormData] = useState({
    id: '',
    code: '',
    article: '',
    price: '',
    vat: '',
    status: '',
    companyid: ''
  });

  // 弹窗打开时,根据用户id获取数据并填充表单
  useEffect(() => {
    if (isEditOpen && user?.id) {
      const fetchUserData = async () => {
        try {
          const userDetail = await getUsers(user.id);
          setFormData({
            id: userDetail.id,
            code: userDetail.code || '',
            article: userDetail.article || '',
            price: userDetail.price || '',
            vat: userDetail.vat || '',
            status: userDetail.status || '',
            companyid: userDetail.companyid || ''
          });
        } catch (error) {
          console.error('获取用户详情失败:', error);
        }
      };
      fetchUserData();
    }
  }, [isEditOpen, user?.id]);

  const handleEditShow = () => {
    setIsEditOpen(true);
  };

  const handleEditClose = () => {
    setIsEditOpen(false);
  };

  // 统一处理所有输入框的变化
  const handleInputChange = (e) => {
    const { name, value } = e.target;
    setFormData(prev => ({ ...prev, [name]: value }));
  };

  const handleEdit = async () => {
    try {
      await editUser(formData.id, formData);
      // 可在此添加成功提示,或通知父组件更新用户列表
    } catch (error) {
      console.error('更新用户数据失败:', error);
    }
  };

  return (
    <>
      <CButton
        style={{
          marginRight: '10px',
          color: 'info',
          border: 'none',
          boxShadow: `2px 2px 9px -3px rgba(0,0,0,0.6)`
        }}
        onClick={handleEditShow}
      >
        Edit
      </CButton>
      <CModal
        visible={isEditOpen}
        onClose={handleEditClose}
        backdrop={'static'}
        keyboard={false}
        portal={false}
      >
        <CModalHeader>
          <CModalTitle>Edit User:</CModalTitle>
        </CModalHeader>
        <CModalBody>
          <CForm>
            <CFormInput
              type="text"
              label="Code:"
              placeholder="Enter Code"
              name="code"
              onChange={handleInputChange}
              value={formData.code}
              className="mb-3"
            />
            <CFormInput
              type="text"
              label="Article:"
              placeholder="Enter Article"
              name="article"
              onChange={handleInputChange}
              value={formData.article}
              className="mb-3"
            />
            <CFormInput
              type="number"
              label="Price:"
              placeholder="Enter Price"
              name="price"
              onChange={handleInputChange}
              value={formData.price}
              className="mb-3"
            />
            <CFormInput
              type="number"
              label="VAT:"
              placeholder="Enter VAT"
              name="vat"
              onChange={handleInputChange}
              value={formData.vat}
              className="mb-3"
            />
            <CFormInput
              type="text"
              label="Status:"
              placeholder="Enter Status"
              name="status"
              onChange={handleInputChange}
              value={formData.status}
              className="mb-3"
            />
            <CFormInput
              type="text"
              label="Company ID:"
              placeholder="Enter Company ID"
              name="companyid"
              onChange={handleInputChange}
              value={formData.companyid}
            />
          </CForm>
        </CModalBody>
        <CModalFooter>
          <CButton color="secondary" onClick={handleEditClose}>
            Cancel
          </CButton>
          <CButton
            color="primary"
            onClick={() => {
              handleEdit();
              handleEditClose();
            }}
          >
            Update
          </CButton>
        </CModalFooter>
      </CModal>
    </>
  );
};

export default DialogEditUser;

关键修正点说明

  • Props接收优化:改为解构{ user },明确接收父组件传入的用户数据,避免props层级混乱。
  • 状态统一管理:用formData对象管理所有表单字段,替代零散的状态变量,更易维护。
  • 数据填充时机:在弹窗打开时触发API请求,获取对应用户数据并更新表单状态,确保打开弹窗时数据已填充。
  • 受控组件实现:输入框使用value绑定状态,而非defaultValue,保证表单数据与状态实时同步。
  • API逻辑优化:getUsers根据id请求单个用户数据,并返回响应体;添加错误抛出,让组件可以捕获并处理异常。
  • 输入处理简化:用统一的handleInputChange处理所有输入框变化,减少重复代码。

内容的提问来源于stack exchange,提问作者Darkpsinight

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 05:01:05