React按钮点击事件中console.log无法获取更新后状态的问题
问题原因
你遇到的是React的闭包陷阱:当点击add user创建user对象时,showName按钮的onClick回调会捕获当前作用域下的name值(此时是空字符串)。后续name更新触发组件重新渲染,但已经存入users数组的按钮仍绑定着旧闭包里的name,所以打印的始终是初始值。
解决方案
以下是两种可行的解决方式:
方案一:用useRef保存最新的name状态
useRef的.current属性会始终指向最新的值,不会被闭包固定:
export default function App() { const [users, setUsers] = React.useState([]); const [name, setName] = React.useState(''); const nameRef = React.useRef(name); // 同步name状态到ref React.useEffect(() => { nameRef.current = name; }, [name]); const addUser = () => { const obj = { name: 'old user name', updateName: ( <button onClick={() => setName('new user name')}>update name</button> ), showName: <button onClick={() => console.log(nameRef.current)}>show name</button>, }; setUsers([obj, ...users]); }; return ( <div> <button onClick={addUser}> add user</button> {users && users.map((user) => ( <div key={user.name}> {user.name} {user.updateName} {user.showName} </div> ))} </div> ); }
方案二:不在users中存储JSX,只存数据,渲染时动态生成按钮
这种方式更符合React数据驱动视图的逻辑,每次组件渲染都会生成新的按钮,自然能拿到最新的name:
export default function App() { const [users, setUsers] = React.useState([]); const [name, setName] = React.useState(''); const addUser = () => { // 仅存储数据,不存储JSX const obj = { id: Date.now(), // 添加唯一id作为列表key name: 'old user name', }; setUsers([obj, ...users]); }; return ( <div> <button onClick={addUser}> add user</button> {users.map((user) => ( <div key={user.id}> {user.name} <button onClick={() => setName('new user name')}>update name</button> <button onClick={() => console.log(name)}>show name</button> </div> ))} </div> ); }
补充说明
方案二更推荐,因为它遵循了React数据与视图分离的核心思想,代码更易维护,从根源上避免了闭包陷阱。如果业务需求必须在users中存储JSX,方案一的useRef方式可以有效解决闭包捕获旧值的问题。
内容的提问来源于stack exchange,提问作者rajasekhar gandavarapu
相关产品推荐
相关产品推荐

