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

React+TypeScript下拉框onChange字段更新异常问题求助

问题解决:Dropdown重复选择同一项时输入框才正确显示

问题原因

  1. Dropdown事件参数处理错误:你当前依赖href字符串分割获取游戏ID,但React-Bootstrap的Dropdown组件onSelect事件的参数并非href值,而是菜单项的eventKey(未设置时可能是点击事件对象,导致首次处理逻辑异常)。
  2. forEach循环无法终止迭代:使用forEach查找游戏时,return仅跳过当前循环,若存在多个ID匹配的游戏,会覆盖之前的结果,导致首次选择时显示错误。
  3. 重复选择同一项不触发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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 07:30:52