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

React Query对接双API时点击同义词更新单词报错排查

问题根因
  1. 核心报错来自Synonyms组件的事件参数冲突:你写的onClick={(item) => {setword(item)}}中,形参item实际是DOM点击事件对象,不是遍历到的同义词字符串。把事件对象作为查询词传给API,接口收到的是无效参数,直接触发请求错误。
  2. Word组件中用组件内普通变量synarray配合push存同义词属于React反模式:每次组件重渲染synarray都会被重置为空数组,在渲染流程中调用getsynonym往数组里写值会导致状态不一致、渲染异常。
  3. 错误分支的JSX里直接写{setword("run")}会在渲染阶段直接触发状态更新,引发无限重渲染循环。
修复方案
  • 修复Synonyms组件点击事件的参数冲突,不要和map遍历的词条变量重名,点击时传入遍历到的同义词字符串
  • 用useMemo基于接口返回数据计算派生的同义词、释义内容,不要在渲染过程中手动修改普通数组
  • 把错误场景下重置单词的逻辑放到useEffect里执行,禁止在JSX渲染阶段直接调用状态更新函数
  • 读取接口嵌套属性时加可选链校验,避免接口返回结构不符合预期时触发读属性报错

修复后代码

Synonyms.jsx

import React from "react";

const Synonyms = ({ synonymarray, setword }) => {
  return (
    <ul>
      {synonymarray?.map((wordItem, i) => (
        <li
          key={i}
          style={{ cursor: "pointer" }}
          onClick={() => {
            setword(String(wordItem));
          }}
        >
          {wordItem}
        </li>
      ))}
    </ul>
  );
};

export default Synonyms;

Word.jsx

import { useState, useMemo, useEffect } from "react";
// 其余第三方组件、方法导入保持原有内容不变

const Word = ({ fetchWord, fetchsynonym }) => {
  const [word, setword] = useState("run");

  const { data, isLoading, isFetching, isError } = useQuery(
    ["definition", word],
    () => fetchWord(word)
  );
  const {
    data: Sdata,
    isLoading: Sloading,
    isFetching: Sfetching,
    isError: Serror,
  } = useQuery(["synonym", word], () => fetchsynonym(word));

  // 计算同义词数组
  const synarray = useMemo(() => {
    if (Sloading || Sfetching || Serror || !Sdata?.noun?.syn) {
      return [];
    }
    return Sdata.noun.syn.slice(0, 3).filter(Boolean);
  }, [Sdata, Sloading, Sfetching, Serror]);

  // 计算释义内容
  const definition = useMemo(() => {
    if (isLoading || isFetching) return "";
    if (isError || !data?.[0]?.meanings?.[0]?.definitions?.[0]?.definition) return "";
    return data[0].meanings[0].definitions[0].definition;
  }, [data, isLoading, isFetching, isError]);

  const handleTranscript = (transcript) => {
    if (!transcript || transcript.length === 0) return;
    setword(String(transcript).trim());
  };

  // 错误场景下重置默认词
  useEffect(() => {
    if (isError) {
      setTimeout(() => setword("run"), 2000);
    }
  }, [isError]);

  return (
    <VStack w={"100%"}>
      {isError ? (
        <>
          <Heading>{word}</Heading>
          <Voice
            handleTranscript={handleTranscript}
            setword={setword}
            word={word}
          />
          <p>请求出错,请重试,仅支持查询单个英文单词</p>
        </>
      ) : (
        <>
          <Heading mt={"10%"} textAlign={"center"}>
            hi Welcome to WordUp dont know how to spell a word and want to
            know what it means ? Click below.
          </Heading>
          <Flex
            padding={2}
            boxShadow={"0 0 1rem 0 rgba(0, 0, 0, .2)"}
            borderRadius={10}
            flexDir={"column"}
            w={"50%"}
            h={[700, 500, 300]}
            alignItems={"center"}
            justifyContent={"space-around"}
          >
            <Heading> Word: {word}</Heading>
            <Heading padding={10} alignSelf={"center"}>
              {isLoading || isFetching ? "加载中..." : definition}
            </Heading>
            {Sloading || Sfetching ? 
              <p>同义词加载中...</p> : 
              <Synonyms synonymarray={synarray} setword={setword} />
            }
            <Voice
              handleTranscript={handleTranscript}
              setword={setword}
              word={word}
            />
          </Flex>
        </>
      )}
    </VStack>
  );
};

export default Word;
补充说明

之前点击同义词后触发接口报错,本质是事件对象被当成查询词传给了API:React Query会把查询key里的内容做序列化,事件对象序列化后是"[object Object]"字符串,API识别不了这个无效单词直接返回错误。
所有从接口数据、状态派生出来的内容(比如这里的同义词列表、释义文本),不要用普通变量手动维护,用useMemo做计算即可,避免数据不同步。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 09:57:19