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

Electron集成React时传递Props为何获取的是旧State?

问题分析与解决方案

一、为什么Log按钮打印旧的State?

这是React里非常典型的闭包捕获问题。当你把c函数作为props传给Card组件时,这个函数会“记住”它被创建时所在的App组件渲染周期里的cards state值。

每次点击+按钮添加新Card,App组件都会重新渲染,此时会生成一个新的c函数(它捕获了当前最新的cards),但之前已经渲染好的Card组件持有的还是它们被创建时的旧c函数——这些旧函数里的cards依然是当时的旧值,所以点击不同Card的Log按钮会打印出各自创建时刻的state。

二、修复方案:用useRef同步最新State

要让所有Log按钮都能拿到最新的cards,我们可以用useRef来存储最新的state值,因为ref的.current属性是可变的,不会受闭包捕获的限制。修改后的App.js代码如下:

import './App.css';
import Cards from './Cards/Cards'
import { useState, useRef, useEffect } from 'react';
let KEY = 0

export default function App() {
 const [cards, setCards] = useState({})
 // 创建ref来同步最新的cards state
 const cardsRef = useRef(cards);

 // 每次cards更新时,同步ref的current值
 useEffect(() => {
   cardsRef.current = cards;
 }, [cards]);

 const c = () => {
   // 这里访问ref的current,拿到最新的state
   console.log(cardsRef.current)
 }

 const make = () =>{
   const a = <Cards log={c} anID={KEY}/>
   const b = {...cards}
   b[KEY] = a
   KEY += 1
   setCards(b)
 }

 return (
 <div>
 <div className="time-container">
 {Object.values(cards)}
 </div>
 <button className="add-button" onClick={() => make()} >+</button>
 <button className="" onClick={() => console.log(cards)} >-</button>
 </div>
 );
}

三、关于存储React元素的优化建议

直接把React元素存在state里并不是最优的做法,React的设计理念是数据驱动UI,state应该存储的是数据,而不是UI组件本身。

推荐的做法是:在state里存储每个Card的核心数据(比如id、内容等),渲染时再根据这些数据动态生成Card组件。这样做的好处:

  • 更符合React的设计逻辑,代码可维护性更高
  • 增删单个Card的功能更容易实现
  • 避免因为存储组件带来的闭包、引用等问题

优化后的示例代码:

import './App.css';
import Cards from './Cards/Cards'
import { useState, useRef, useEffect } from 'react';
let KEY = 0

export default function App() {
 // 存储卡片数据,而不是React元素
 const [cardData, setCardData] = useState({})
 const cardDataRef = useRef(cardData);

 useEffect(() => {
   cardDataRef.current = cardData;
 }, [cardData]);

 const log = () => {
   console.log(cardDataRef.current)
 }

 const addCard = () =>{
   // 使用函数式更新,避免闭包问题
   setCardData(prev => ({
     ...prev,
     [KEY]: { id: KEY }
   }))
   KEY += 1
 }

 // 新增删除单个卡片的功能
 const deleteCard = (cardId) => {
   setCardData(prev => {
     const newData = {...prev}
     delete newData[cardId]
     return newData
   })
 }

 return (
 <div>
 <div className="time-container">
 {/* 根据数据动态渲染Card组件 */}
 {Object.values(cardData).map(data => (
   <Cards 
     key={data.id} 
     log={log} 
     anID={data.id}
     onDelete={() => deleteCard(data.id)}
   />
 ))}
 </div>
 <button className="add-button" onClick={addCard} >+</button>
 <button className="" onClick={() => console.log(cardData)} >-</button>
 </div>
 );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 16:52:38