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

React电话本应用联系人编辑功能逻辑及DOM错误排查

React电话本编辑功能问题修复

问题描述

我正在开发React电话本应用,想要实现点击编辑按钮时,显示表单并填入对应联系人的姓名和号码,接收编辑后的信息更新列表。但遇到一个问题:当表单未显示(showForm为false)时,点击编辑按钮会抛出**"Cannot set properties of null (setting 'value')"**错误,只有表单已经显示时功能才正常。

错误原因

  • React的状态更新是异步的,调用setShowForm(true)后,表单不会立刻渲染到DOM中,此时用document.getElementById获取输入框会返回null,导致赋值时报错。
  • 原代码中handleEdit函数错误地将空的userName和number状态赋值给输入框,没有正确获取要编辑的联系人信息。

解决方案

  • 新增editIndex状态,跟踪当前正在编辑的联系人索引(初始为null,表示新增模式)。
  • 点击编辑按钮时,将对应联系人的信息赋值给userName和number状态,同时设置editIndex和showForm。
  • 区分表单的新增/编辑模式:当editIndex不为null时,执行更新联系人操作,而非新增。
  • 移除所有直接操作DOM的代码,完全用React状态驱动UI渲染。

修改后的完整代码

import React, { useState } from "react";

const App = () => {
  const phoneBookData = [{ name: "John Doe", number: 12345678 }];
  const [contacts, setContacts] = useState(phoneBookData);
  const [showForm, setShowForm] = useState(false);
  const [userName, setUserName] = useState("");
  const [number, setNumber] = useState("");
  // 新增状态:跟踪当前编辑的联系人索引,null表示新增模式
  const [editIndex, setEditIndex] = useState(null);

  const handleDelete = (index) => {
    const newContacts = contacts.filter((_, idx) => idx !== index);
    setContacts(newContacts);
  };

  const handleSubmitContact = () => {
    if (!userName.trim()) {
      alert("请输入有效的姓名。");
      return;
    }
    if (/[0-9!@#$%^&*]/.test(userName)) {
      alert("姓名不能包含数字或特殊字符。");
      return;
    }
    if (!number.trim()) {
      alert("请输入有效的号码。");
      return;
    }

    if (editIndex !== null) {
      // 编辑模式:更新指定索引的联系人
      const updatedContacts = [...contacts];
      updatedContacts[editIndex] = { name: userName, number: number };
      setContacts(updatedContacts);
      // 重置编辑状态
      setEditIndex(null);
    } else {
      // 新增模式:添加新联系人
      const newContact = { name: userName, number: number };
      setContacts([...contacts, newContact]);
    }
    // 清空输入框
    setUserName("");
    setNumber("");
  };

  const handleEdit = (index) => {
    // 获取要编辑的联系人信息
    const contactToEdit = contacts[index];
    // 填充表单状态
    setUserName(contactToEdit.name);
    setNumber(contactToEdit.number.toString());
    // 设置编辑索引并显示表单
    setEditIndex(index);
    setShowForm(true);
  };

  // 重置表单为新增模式
  const resetForm = () => {
    setShowForm(false);
    setEditIndex(null);
    setUserName("");
    setNumber("");
  };

  return (
    <div id="main">
      <div className="container-fluid">
        <div className="row">
          <div className="col-md-4"></div>

          <div className="col-md-4">
            <div className="App">
              <h2 className="header">电话本应用</h2>
              <span
                style={{
                  cursor: "pointer",
                  color: "blue",
                  textDecoration: "underline",
                }}
                onClick={resetForm}
              >
                {showForm ? "隐藏表单" : "新建联系人"}
              </span>
              {showForm && (
                <div className="container">
                  <form className="form">
                    <div className="form-group">
                      <input
                        type="text"
                        className="form-control"
                        placeholder="姓名"
                        value={userName}
                        onChange={(e) => setUserName(e.target.value)}
                        id="name"
                        autoFocus
                      />
                    </div>
                    <div className="form-group">
                      <input
                        type="text"
                        className="form-control"
                        placeholder="号码"
                        value={number}
                        onChange={(e) => setNumber(e.target.value)}
                        id="number"
                      />
                    </div>
                    <button
                      type="button"
                      className="btn btn-primary icon-holder"
                      onClick={handleSubmitContact}
                    >
                      {editIndex !== null ? "更新" : "添加"}
                    </button>
                  </form>
                </div>
              )}
              <p>当前共保存 {contacts.length} 个联系人。</p>
              {contacts.map((contact, index) => (
                <div key={index} className="contacts">
                  <div className="contact-details">
                    <h5>
                      {index + 1}) {contact.name}
                    </h5>
                    <p>{contact.number}</p>
                  </div>
                  <button
                    className="icon-holder"
                    onClick={() => handleEdit(index)}
                  >
                    编辑
                  </button>
                  <button
                    className="icon-holder"
                    onClick={() => handleDelete(index)}
                  >
                    删除
                  </button>
                  <hr />
                </div>
              ))}
            </div>
          </div>

          <div className="col-md-4"></div>
        </div>
      </div>
    </div>
  );
};

export default App;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 15:17:05