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

React中useState更新后map方法无法渲染最新联系人数据

问题描述

开发通讯录应用时,通过表单获取用户输入后尝试添加到state,再用map渲染联系人详情。目前遇到的问题是:控制台显示contacts数据已更新,但页面无法通过map渲染最新内容;修改代码触发热更新后,已保存的联系人能正常显示。

import React, { useState, useEffect } from "react";

const phoneBook = [];

const App = () => {
  const [contacts, setContacts] = useState(phoneBook);
  const [showForm, setShowForm] = useState(false);
  const [userName, setUserName] = useState("");
  const [number, setNumber] = useState("");

  const handleDelete = (name) => {
    let newPhoneBook = contacts.filter((contact) => contact.name !== name);
    setContacts(newPhoneBook);
  };

  const handleAddContact = (userName, number) => {
    let obj = { name: userName, number: number };
    console.log("obj:", obj);
    phoneBook.push(obj);

    console.log("contacts:", contacts);
    console.log("phoneBook:", phoneBook);
  };

  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">PhoneBook App</h2>
              <span
                style={{
                  cursor: "pointer",
                  color: "blue",
                  textDecoration: "underline",
                }}
                onClick={() => setShowForm(!showForm)}
              >
                {showForm ? "Hide Contact Form" : "Create New Contact"}
              </span>

              {showForm && (
                <div className="container">
                  <form className="form">
                    <div class="form-group">
                      <input
                        type="text"
                        className="form-control"
                        placeHolder="Name"
                        value={userName}
                        onChange={(e) => {
                          e.target.value;
                          setUserName(e.target.value);
                          console.log("userName:", userName);
                          console.log("e.target.value:", e.target.value);
                        }}
                      />
                    </div>
                    <div class="form-group">
                      <input
                        type="text"
                        className="form-control"
                        placeHolder="Number"
                        value={number}
                        onChange={(e) => {
                          e.target.value;
                          setNumber(e.target.value);
                          console.log("number:", number);
                          console.log("e.target.value:", e.target.value);
                        }}
                      />
                    </div>
                    <button
                      type="button"
                      className="btn btn-primary icon-holder"
                      onClick={() => {
                        handleAddContact(userName, number);
                      }}
                    >
                      Add
                    </button>
                  </form>
                </div>
              )}
              <p>
                There are {contacts.length} contacts saved in this book yet.
              </p>
              {contacts.map((contact, index) => (
                <div key={index} className="contacts">
                  <div class="contact-details">
                    <h5>{contact.name}</h5>
                    <p>{contact.number}</p>
                  </div>
                  <button
                    class="icon-holder"
                    onClick={() => {
                      handleDelete(contact.name);
                    }}
                  >
                    Delete
                  </button>
                  <hr />
                </div>
              ))}
            </div>
          </div>

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

export default App;
解决方案

问题核心是直接修改了外部的phoneBook数组,却没有调用setContacts更新state。React的状态更新依赖setState触发重新渲染,你只是修改了初始的数组变量,state并没有得到更新,所以页面不会重新渲染;而热更新时组件重新初始化,state会重新读取phoneBook的最新值,所以联系人会显示。

修改步骤:

  • 移除全局的phoneBook变量,直接用useState初始化空数组:const [contacts, setContacts] = useState([]);
  • 修改handleAddContact函数,通过setContacts更新state,注意要创建新数组(避免直接修改原state数组):
const handleAddContact = (userName, number) => {
  const newContact = { name: userName, number: number };
  // 用展开运算符创建新数组,添加新联系人
  setContacts(prevContacts => [...prevContacts, newContact]);
  // 可选:清空输入框
  setUserName("");
  setNumber("");
};

额外优化点:

  • 输入框onChange里多余的e.target.value;可以删掉,直接调用setUserName(e.target.value)即可
  • 避免用数组索引作为key,如果联系人名称唯一,用contact.name作为key更稳定

修改后的完整代码:

import React, { useState } from "react";

const App = () => {
  const [contacts, setContacts] = useState([]);
  const [showForm, setShowForm] = useState(false);
  const [userName, setUserName] = useState("");
  const [number, setNumber] = useState("");

  const handleDelete = (name) => {
    setContacts(prevContacts => prevContacts.filter(contact => contact.name !== name));
  };

  const handleAddContact = (userName, number) => {
    const newContact = { name: userName, number: number };
    setContacts(prevContacts => [...prevContacts, newContact]);
    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={() => setShowForm(!showForm)}
              >
                {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)}
                      />
                    </div>
                    <div className="form-group">
                      <input
                        type="text"
                        className="form-control"
                        placeholder="号码"
                        value={number}
                        onChange={(e) => setNumber(e.target.value)}
                      />
                    </div>
                    <button
                      type="button"
                      className="btn btn-primary icon-holder"
                      onClick={() => handleAddContact(userName, number)}
                    >
                      添加
                    </button>
                  </form>
                </div>
              )}
              <p>
                当前通讯录共有 {contacts.length} 个联系人
              </p>
              {contacts.map((contact) => (
                <div key={contact.name} className="contacts">
                  <div className="contact-details">
                    <h5>{contact.name}</h5>
                    <p>{contact.number}</p>
                  </div>
                  <button
                    className="icon-holder"
                    onClick={() => handleDelete(contact.name)}
                  >
                    删除
                  </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 11:45:05