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

React父组件向子组件传值时子端接收数据与父端不一致问题

问题根因

你遇到的现象本质是父组件每次重新渲染时都会重新执行randomSelect()生成新的随机ID,导致传给子组件的飞船数据被替换。
你的playerOneId、computerId是直接定义在父组件函数体中的普通变量,只要父组件触发重渲染(比如你调用setResult、setPlayerScore、setPlayerSelected更新状态时),这两个变量就会被重新赋值,对应的playerOneShip、computerShip自然也会变化。
你觉得父组件的console.log(1)打印正常,大概率是你只注意到了第一次渲染的输出,实际上每次父组件重渲染时这个打印的内容也会同步更新,和子组件拿到的props是一致的。

修复方案

你只需要把生成的随机ID存到状态里,避免每次渲染都重新生成即可,这里给两种可行方案:

方案1:在获取到飞船数据后生成随机ID存入状态

修改父组件的状态定义和useEffect逻辑:

// 新增两个状态存储玩家和电脑的选中ID
const [playerOneId, setPlayerOneId] = useState(null);
const [computerId, setComputerId] = useState(null);

useEffect(() => {
    fetch('https://connectr-swapi.herokuapp.com/', {
        method: "POST",
        headers: {"Content-Type": "application/json"},
        body: JSON.stringify({query: STARSHIP_QUERY})
    })
    .then(response => response.json())
    .then(data => {
        const starships = data.data.allStarships.starships;
        setStarships(starships);
        // 拿到数据后再生成随机ID
        const starShipIds = starships.map(ship => ship.id);
        const randomSelect = () => {
            const random = Math.floor(Math.random() * starShipIds.length);
            return starShipIds[random];
        }
        setPlayerOneId(randomSelect());
        setComputerId(randomSelect());
    })
    .catch(error => console.log({'Error': error}))
    
},[])

然后删除原来写在函数体里的randomSelect、starShipIds、valueOneID、valueTwoID相关的普通变量定义即可,后续父组件因为其他状态更新重渲染时,这两个ID不会变化,传给子组件的飞船数据也就不会变了。

方案2:用useMemo缓存随机ID

如果你不想改状态,也可以用useMemo缓存生成结果,只有当starships变化时才重新生成:

import { useMemo } from 'react';

// 把原来的普通变量定义替换成useMemo
const {playerOneId, computerId, playerOneShip, computerShip} = useMemo(() => {
    if(starships.length === 0) return {
        playerOneId: null,
        computerId: null,
        playerOneShip: [],
        computerShip: []
    }
    const starShipIds = starships.map(ship => ship.id);
    const randomSelect = () => {
        const random = Math.floor(Math.random() * starShipIds.length);
        const selectedId = starShipIds[random];
        return selectedId;
    }
    const playerOneId = randomSelect();
    const computerId = randomSelect();
    return {
        playerOneId,
        computerId,
        playerOneShip: starships.filter(ship => ship.id === playerOneId),
        computerShip: starships.filter(ship => ship.id === computerId)
    }
}, [starships]); // 只有starships变化时才会重新计算

这种方案同样可以避免其他状态更新导致随机ID被重新生成的问题。

额外优化建议

你当前的代码在starships为空时调用randomSelect会出现starShipIds.length为0的情况,生成的随机数是NaN,返回的ID是undefined,上面的两种方案都已经规避了这个问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 12:18:03