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
相关产品推荐
相关产品推荐

