React+TypeScript下拉框onChange字段更新异常问题求助
问题解决:Dropdown重复选择同一项时输入框才正确显示
问题原因
- Dropdown事件参数处理错误:你当前依赖
href字符串分割获取游戏ID,但React-Bootstrap的Dropdown组件onSelect事件的参数并非href值,而是菜单项的eventKey(未设置时可能是点击事件对象,导致首次处理逻辑异常)。 - forEach循环无法终止迭代:使用
forEach查找游戏时,return仅跳过当前循环,若存在多个ID匹配的游戏,会覆盖之前的结果,导致首次选择时显示错误。 - 重复选择同一项不触发onSelect:React-Bootstrap的
Dropdown默认不会对重复选中的同一项触发onSelect事件,你之前添加的错误useEffect反而干扰了状态更新。
修复步骤
1. 给Dropdown.Item添加eventKey属性
将游戏ID直接作为eventKey传递,无需解析href:
<Dropdown.Item key={"idx_" + game.id} eventKey={game.id} // 添加这行,直接传递游戏ID href={"#/action-" + game.id} > {game._datetime} <b>{game.host_name} - {game.visitor_name}</b> </Dropdown.Item>
2. 重构handleGameSelect逻辑
用find替代forEach,直接定位匹配的游戏,同时简化参数处理:
const handleGameSelect = React.useCallback((gameId: string | number) => { if (!gameId) return; const selectedGame = props.games.find(game => String(game.id) === String(gameId)); if (selectedGame) { const gameName = `${selectedGame._datetime} ${selectedGame.host_name} - ${selectedGame.visitor_name}`; setGame(gameName); } }, [props.games])
3. 移除错误的useEffect代码
你添加的useEffect会在game状态变化时调用handleGameSelect(undefined),导致输入框被清空,直接删除即可。
4. (可选)允许重复选择同一项触发事件
如果需要重复点击同一项也能触发更新,可以给Dropdown.Item添加onClick事件,替代(或补充)Dropdown的onSelect:
<Dropdown.Item key={"idx_" + game.id} eventKey={game.id} href={"#/action-" + game.id} onClick={() => handleGameSelect(game.id)} // 直接调用处理函数 > {game._datetime} <b>{game.host_name} - {game.visitor_name}</b> </Dropdown.Item>
同时可以移除Dropdown组件上的onSelect属性。
修复后的完整组件代码
// worldcup-app/src/components/world-cup.tsx // Import deps import React, { useState } from 'react' import { WorldCupGameIF } from '../results/world-cup-game' // Import styles import '../../styles/worldcup.css' import { Dropdown } from 'react-bootstrap' export interface WorldCupScoreIF { games: WorldCupGameIF[] loading: boolean; } // Create Score component export const WorldCupScoreEntry = (props: WorldCupScoreIF) => { // Prepare states const [game, setGame] = useState('') // 用const替代let,符合React规范 // Submit new book const handleGameSelect = React.useCallback((gameId: string | number) => { if (!gameId) return; const selectedGame = props.games.find(game => String(game.id) === String(gameId)); if (selectedGame) { const gameName = `${selectedGame._datetime} ${selectedGame.host_name} - ${selectedGame.visitor_name}`; setGame(gameName); } }, [props.games]) return ( <div className="list-wrapper"> {/* Form for creating new book */} <div className="list-form"> <div className="form-wrapper"> <div className="form-row"> <input className="form-input" type="text" id="game" name="game" value={game} disabled /> </div> <div className="form-row"> <Dropdown> <Dropdown.Toggle variant="primary" id="dropdown-basic"> Select Game </Dropdown.Toggle> <Dropdown.Menu> {props.games.length > 0 ? ( props.games.map((game: WorldCupGameIF) => ( <Dropdown.Item key={"idx_" + game.id} eventKey={game.id} href={"#/action-" + game.id} onClick={() => handleGameSelect(game.id)} > {game._datetime} <b>{game.host_name} - {game.visitor_name}</b> </Dropdown.Item> )) ) : ( <div className="dropdown-item">There are no results yet.</div> {/* 替换为符合Dropdown.Menu的元素,不要用tr/td */} )} </Dropdown.Menu> </Dropdown> </div> </div> </div> </div> ) }
注:原空状态使用的tr/td不符合Dropdown.Menu的DOM结构,已替换为适配的div元素,保证样式和结构一致性。
内容的提问来源于stack exchange,提问作者Slawek
相关产品推荐
相关产品推荐

