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

React开发:通过matchId匹配已保存预测值回填赛事比分输入框

问题原因

你现在的匹配逻辑完全依赖数组索引、Object.keys()返回的键顺序,这种方式天生不稳定——只要赛事列表排序调整、预测数据增删、对象键枚举顺序和预期不一致,就会出现回填数据错位。
你的SAVED_PREDICTIONS本身就是以赛事id为键存储的,根本不需要绕弯用索引做匹配,直接拿当前渲染赛事的id当键取值即可。

修复方案

核心修改点

  • 删除PredictField组件内通过Object.keys取键名再按innerIndex找值的逻辑,直接使用当前赛事的id作为键,从预测数据对象中取对应记录
  • 补全useEffect依赖数组,解决预测数据异步从Firestore加载完成后,输入框值不更新的问题
  • 增加空值容错,避免预测数据不存在时抛出JS错误
  • 修复原输入框取值的隐式类型问题,避免输入值存成字符串

修改后的PredictField组件代码

import { useEffect, useState } from "react";
import { useSelector } from "react-redux";

export const PredictField = (props: any) => {
    const { fixture, onchange, index } = props;
    const predictions = useSelector((state: any) => state.predictForm);
    const [home, setHome] = useState(0);
    const [away, setAway] = useState(0);

    useEffect(() => {
        // 先判断对应比赛日的预测数据是否存在
        const matchDayPredictions = predictions.userPredictions?.[0]?.[index];
        if (!matchDayPredictions) {
            setHome(0);
            setAway(0);
            return;
        }
        // 直接用当前赛事id当键取对应预测,完全不依赖索引
        const currentMatchPrediction = matchDayPredictions[fixture.id];
        if (!currentMatchPrediction) {
            setHome(0);
            setAway(0);
            return;
        }
        // 回填比分,null/undefined值兜底为0
        setHome(currentMatchPrediction.score.fullTime.homeTeam ?? 0);
        setAway(currentMatchPrediction.score.fullTime.awayTeam ?? 0);
    // 相关值变化时自动重新匹配回填
    }, [fixture.id, predictions, index]);

    const handleOnChangeHome = (e: any) => {
        const value = Number(e.value) || 0;
        setHome(value);
        onchange(e);
    };
    const handleOnChangeAway = (e: any) => {
        const value = Number(e.value) || 0;
        setAway(value);
        onchange(e);
    };

    return (
        <div>
            <p>
                {fixture.matchday}, {fixture.id}
            </p>
            <label>{fixture.homeTeam.name.replace("FC", "")}</label>
            <input
                name={`homeTeam-${fixture.id}`}
                type="number"
                value={home}
                onChange={(e) => handleOnChangeHome(e.target)}
            />
            <input
                name={`awayTeam-${fixture.id}`}
                type="number"
                value={away}
                onChange={(e) => handleOnChangeAway(e.target)}
            />
            <label>{fixture.awayTeam.name.replace("FC", "")}</label>
        </div>
    );
};

可选优化

Predict组件遍历赛事列表时,原来的key用的是数组索引i,建议改成赛事id当key,避免列表重排时出现组件状态复用错误,同时可以删掉没用的innerIndex传参:

{fixture.map((el: any) => (
    <PredictField
        key={el.id}
        allFixtures={data}
        fixture={el}
        predictions={predictions}
        matchDay={el.matchday}
        index={index}
        onchange={onchange}
    />
))}

通过业务唯一ID匹配关联数据的方式,不会受列表排序、数据增删的影响,稳定性远高于索引匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 16:48:54