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

Next.js中onClick按钮调用build函数无效问题排查与优化

问题原因分析
  1. picked不是React状态变量:你用let picked声明的是普通变量,React不会追踪它的变化。点击Build按钮调用build()时,虽然修改了picked的值,但组件不会触发重渲染,页面网格自然不会更新。
  2. 滑块能更新的核心原因:滑块改变时会调用setValue更新value状态,触发组件重渲染,此时picked = build()会重新执行,生成新数组并渲染,所以滑块操作能生效。
  3. 闭包隐患:build函数依赖外部的picked和value,多次调用可能因闭包捕获旧值导致逻辑异常。
优化方案

1. 将picked改为React状态

用useState声明picked,让React追踪它的变化,更新时调用状态更新函数触发重渲染。

2. 重构build函数

让build函数根据当前value生成全新数组,不依赖外部的picked变量,避免可变状态和闭包问题。

3. 调整按钮点击逻辑

点击Build按钮时,调用状态更新函数,传入新生成的队伍数组。

修正后的完整代码

function formTeam() {
  const agents = [
    "Astra", "Breach", "Brimstone", "Chamber", "Cypher",
    "Jett", "KayO", "Killjoy", "Neon", "Omen",
    "Phoenix", "Raze", "Reyna", "Sage", "Skye",
    "Sova", "Fade", "Viper", "Yoru",
  ];
  // 初始化value为2,匹配滑块最小值
  const [value, setValue] = React.useState(2);
  // 初始化picked为5个QuestionMark的数组
  const [picked, setPicked] = React.useState(Array(5).fill("QuestionMark"));

  const handleChange = (newValue) => setValue(newValue);

  // 重构build函数,返回新生成的队伍数组
  const buildTeam = () => {
    const newPicked = Array(5).fill("QuestionMark");
    const clone = [...agents];
    for (let i = 0; i < value; i++) {
      const randomIndex = Math.floor(Math.random() * clone.length);
      newPicked[i] = clone[randomIndex];
      clone.splice(randomIndex, 1);
    }
    return newPicked;
  };

  // 点击按钮时更新picked状态
  const handleBuildClick = () => {
    setPicked(buildTeam());
  };

  // 组件挂载或value变化时自动生成队伍,保持滑块改变时的自动更新逻辑
  React.useEffect(() => {
    setPicked(buildTeam());
  }, [value]);

  return (
    <div>
      <FormControl>
        <Center>
          <FormLabel>Players</FormLabel>
          <NumberInput
            max={5}
            min={2}
            value={value}
            onChange={handleChange}
            w={"500px"}
          >
            <NumberInputField />
            <NumberInputStepper>
              <NumberIncrementStepper />
              <NumberDecrementStepper />
            </NumberInputStepper>
          </NumberInput>
        </Center>
      </FormControl>

      <Center>
        <Button onClick={handleBuildClick}>
          Build
        </Button>
      </Center>
      
      <Grid templateColumns={"repeat(5, 1fr)"} gap={20} mt={20}>
        {picked.map((agent, index) => (
          <GridItem key={index} w={"150px"}>
            <AgentCard image={`/images/valorant/agents/${agent}.png`} />
          </GridItem>
        ))}
      </Grid>
    </div>
  );
}

额外优化点

  • 给map渲染的元素加上key属性,符合React渲染规范。
  • 用useEffect监听value变化,自动生成队伍,保留滑块改变时的自动更新逻辑。
  • 把agents声明为const,因为它是固定不变的常量。
  • 初始化value为2,避免初始时value为0导致没有生成任何agent的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 15:05:20