如何在全局变量变化时更新React组件GameData?
问题
我有一个名为GameData的React组件,用于在表格中点击足球比赛条目时展示该比赛的详情。表格属于另一个组件,它会更新GameData组件用于展示数据的全局变量gameToDisplay。由于该变量是全局的,在GameData内部使用useState()无法生效。目前通过按钮控制显示的方式需要点击两次才能更新数据,我希望在gameToDisplay变化时,自动更新<p className='data'>中的数据并让组件重新渲染,该如何实现?
当前代码
let gameToDisplay = {}; function displayGameData(gameId) { gameToDisplay = gameData.find(game => game.id === gameId); // 点击表格中的比赛时会执行这个函数,这部分更新正常工作 } function GameData() { const [gdDisplay, setgdDisplay] = useState(true); function handleDetailClick() { setgdDisplay(!gdDisplay); } return ( <div className='GameData box'> <h2>Game Details</h2> <div className='Links'> <ButtonGroup variant="contained" aria-label="outlined primary button group"> <Button onClick={handleDetailClick}>{gdDisplay ? 'Less' : 'More'} details</Button> </ButtonGroup> </div> {gdDisplay ? ( <p className='data'> // 从gameToDisplay获取数据进行展示 </p> ) : ( <></> )} </div> ) }
解决方案
方法1:状态提升(推荐)
全局变量无法触发React组件的重渲染,最优方案是把gameToDisplay的状态放到两个组件的共同父组件中,通过props传递给子组件:
- 在共同父组件中维护状态并传递给子组件:
import { useState } from 'react'; function ParentComponent() { const [gameToDisplay, setGameToDisplay] = useState({}); // 点击表格比赛时调用的函数,更新选中的比赛数据 const handleGameClick = (gameId) => { const selectedGame = gameData.find(game => game.id === gameId); setGameToDisplay(selectedGame); }; return ( <div> {/* 表格组件接收点击回调 */} <TableComponent onGameSelect={handleGameClick} /> {/* GameData组件接收选中的比赛数据 */} <GameData selectedGame={gameToDisplay} /> </div> ); }
- 修改
GameData组件,直接使用props中的数据:
function GameData({ selectedGame }) { const [gdDisplay, setgdDisplay] = useState(true); function handleDetailClick() { setgdDisplay(!gdDisplay); } return ( <div className='GameData box'> <h2>Game Details</h2> <div className='Links'> <ButtonGroup variant="contained" aria-label="outlined primary button group"> <Button onClick={handleDetailClick}>{gdDisplay ? 'Less' : 'More'} details</Button> </ButtonGroup> </div> {gdDisplay ? ( Object.keys(selectedGame).length > 0 ? ( <p className='data'> {/* 根据你的数据结构展示内容 */} 主队:{selectedGame.homeTeam},客队:{selectedGame.awayTeam} </p> ) : ( <p>请选择一场比赛查看详情</p> ) ) : ( <></> )} </div> ) }
- 修改表格组件,点击时调用父组件传递的回调:
function TableComponent({ onGameSelect }) { return ( <table> {gameData.map(game => ( <tr key={game.id} onClick={() => onGameSelect(game.id)}> <td>{game.homeTeam} vs {game.awayTeam}</td> </tr> ))} </table> ); }
方法2:监听全局变量(仅应急使用)
如果暂时无法重构状态提升,可以通过useEffect手动触发重渲染,但这种方式耦合度高,不推荐长期使用:
import { useState, useEffect } from 'react'; let gameToDisplay = {}; function displayGameData(gameId) { gameToDisplay = gameData.find(game => game.id === gameId); } function GameData() { const [gdDisplay, setgdDisplay] = useState(true); // 用一个状态变量触发重渲染 const [renderKey, setRenderKey] = useState(0); useEffect(() => { // 重写displayGameData,修改全局变量后触发重渲染 const originalDisplay = displayGameData; displayGameData = (gameId) => { originalDisplay(gameId); setRenderKey(prev => prev + 1); }; // 组件卸载时恢复原函数 return () => { displayGameData = originalDisplay; }; }, []); function handleDetailClick() { setgdDisplay(!gdDisplay); } return ( <div className='GameData box' key={renderKey}> <h2>Game Details</h2> <div className='Links'> <ButtonGroup variant="contained" aria-label="outlined primary button group"> <Button onClick={handleDetailClick}>{gdDisplay ? 'Less' : 'More'} details</Button> </ButtonGroup> </div> {gdDisplay ? ( Object.keys(gameToDisplay).length > 0 ? ( <p className='data'> 主队:{gameToDisplay.homeTeam},客队:{gameToDisplay.awayTeam} </p> ) : ( <p>请选择一场比赛查看详情</p> ) ) : ( <></> )} </div> ) }
核心说明
- React组件只有在自身状态(
useState)或props变化时才会重渲染,全局变量修改不会触发这个机制,必须用React的状态管理方式。 - 状态提升是React组件间共享状态的标准方案,代码更易维护和调试,优先采用。
内容的提问来源于stack exchange,提问作者ajmcallister27
相关产品推荐
相关产品推荐

