React中useRef获取循环渲染input值为空的问题解决
问题:点击Save按钮后newLink输出为空的解决方法
问题原因
你在循环渲染多个<input>时,所有输入框都绑定了同一个link ref。React中,同一个ref被多个DOM元素复用的话,最终只会指向最后一个被渲染的DOM元素。所以当你点击前面的Save按钮时,link.current指向的是最后一个输入框,而非当前按钮对应的那个,自然拿不到正确的值,甚至为空。
解决方案
方案一:使用受控组件(推荐)
用state跟踪每个社交平台的链接,这是React中处理表单输入的标准方式,更易维护和扩展。
import React, { useState } from 'react'; import "./User.css" export default function User() { const objArray = [ { class: "fa fa-envelope", title: "Gmail", color: "red" }, { class: "fa fa-facebook", title: "Facebook", color: "blue" }, { class: "fa fa-instagram", title: "Instagram", color: "#E4405F" }, ]; // 初始化state,为每个平台存储链接 const [links, setLinks] = useState(() => objArray.reduce((acc, item) => { acc[item.title] = ""; return acc; }, {}) ); // 处理输入框内容变化 const handleInputChange = (title, value) => { setLinks(prev => ({ ...prev, [title]: value })); }; const handleSave = (className, title, color) => { const newLink = links[title]; console.log("this is -> ", className, title, color, newLink); // 这里执行保存到firebase的逻辑 }; return ( <main className="User_main"> <h1>~ Customization ~</h1> <h2>Profile Section</h2> <br /> <h2 style={{ marginBottom: "0px" }} > ~ Add Social Media Icons ~ </h2> <small>Click and add the social media links</small> <br /><br /> <div className="socialIcons"> {objArray.map((e) => ( <div key={e.title}> {/* 添加key,避免React渲染警告 */} <i style={{ color: `${e.color}`, border: "1px solid " }} className={e.class} /> <h4>{e.title}</h4> <input value={links[e.title]} onChange={(event) => handleInputChange(e.title, event.target.value)} placeholder="Enter link here" type="url" /> <br /> <button onClick={() => handleSave(e.class, e.title, e.color)}>Save</button> </div> ))} </div> </main> ) }
方案二:使用ref数组
如果偏好非受控组件,可以创建一个ref数组,让每个输入框对应独立的ref。
import React, { useRef } from 'react'; import "./User.css" export default function User() { const objArray = [ { class: "fa fa-envelope", title: "Gmail", color: "red" }, { class: "fa fa-facebook", title: "Facebook", color: "blue" }, { class: "fa fa-instagram", title: "Instagram", color: "#E4405F" }, ]; // 创建ref数组,每个元素对应一个输入框的ref const linkRefs = useRef(objArray.map(() => React.createRef())); const handleSave = (index, className, title, color) => { const newLink = linkRefs.current[index].current.value; console.log("this is -> ", className, title, color, newLink); // 执行保存到firebase的逻辑 }; return ( <main className="User_main"> <h1>~ Customization ~</h1> <h2>Profile Section</h2> <br /> <h2 style={{ marginBottom: "0px" }} > ~ Add Social Media Icons ~ </h2> <small>Click and add the social media links</small> <br /><br /> <div className="socialIcons"> {objArray.map((e, index) => ( <div key={e.title}> <i style={{ color: `${e.color}`, border: "1px solid " }} className={e.class} /> <h4>{e.title}</h4> <input ref={linkRefs.current[index]} placeholder="Enter link here" type="url" /> <br /> <button onClick={() => handleSave(index, e.class, e.title, e.color)}>Save</button> </div> ))} </div> </main> ) }
方案对比
- 方案一(受控组件):符合React单向数据流理念,便于跟踪状态变化,支持表单验证、实时同步等场景,推荐使用。
- 方案二(ref数组):属于非受控组件,适合简单场景,但状态管理不如受控组件清晰。
内容的提问来源于stack exchange,提问作者Ankit
相关产品推荐
相关产品推荐

