useState数组对象

14

我有一个搜索框,可以复制和粘贴来自Excel的列。我解析输入并生成条目的数组。

然后,我正在映射这些条目,并使用每个项目调用自定义钩子,从我的graphql端点获取一些数据。

例如:

搜索框提供了3个条目:

["D38999/26", "LJT06RE25-61PA", "D38999/46FJ61AA"]

fetchData函数将其中之一作为查询参数接收。当前,此过程将返回3个单独的对象,如下所示:

{query: "D38999/26", cables: Array(35)}
{query: "LJT06RE25-61PA", cables: Array(1)}
{query: "D38999/46FJ61AA", cables: Array(1)}

如何设置一个React Hook,以便允许我将每个对象作为对象数组附加到result状态中?

我的最终目标是获得这样的一个对象数组:

[
{query: "D38999/26", cables: Array(35)},
{query: "LJT06RE25-61PA", cables: Array(1)},
{query: "D38999/46FJ61AA", cables: Array(1)}
]

这是我当前使用的自定义钩子来解析我的API端点

const useCableMatch = () => {
  const [result, setResult] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [isError, setIsError] = useState(false);
  const client = useApolloClient();

  const fetchData = async query => {
    setIsError(false);
    setIsLoading(true);
    try {
      const { data } = await client.query({
        query: GET_VALID_CABLE,
        variables: { pn: `%${query}%` },
      });

      const response = { query, ...data };
      console.log('response:', response);

      setResult(response);
    } catch (error) {
      setIsError(true);
    }
    setIsLoading(false);
  };

  return [{ result, isLoading, isError }, fetchData];
};

目前setResult的设置仅返回来自响应的单个对象。我希望返回一个数组,其中包含每个生成的对象附加到现有对象数组中。


2
也许可以使用解构赋值?setResult([...result, response]) - AronNeewart
1
React函数组件必须是纯粹的props函数。就像任何状态都必须包装在对useState的调用中一样,任何副作用必须包装在对useEffect的调用中。或者只需使用类组件。 - Jared Smith
3个回答

31

假设response可以直接添加到result数组中,你可以:

setResult(result => [...result, response]);

这将使用数组展开运算符将新的response添加到先前的result状态中。


3
这个行得通!我好奇为什么 setResult(result => [...result, response]); 行得通,但是 setResult([...result, response]); 却不行。 - Jeremy London
@JeremyLondon 为设置状态是异步的。该符号确保使用 result 的先前状态。 - Joseph D.
1
点赞。如果您在result中更新了某个值并需要重新渲染,只需执行setResult(result => [...result])即可。将其视为一种刺激以引起渲染。 - Fakeer
1
谢谢!我曾经因为使用.push()将新元素添加到现有状态数组中并尝试将其设置在子组件的状态中时,苦于我的子组件无法更新。尽管它仍然能够工作,但是依赖于该数组的子组件并没有像预期那样立即重新渲染(它只会在随后的渲染或强制渲染时才会重新渲染)。 - Rob
1
今天我学到了新东西,谢谢你。 - Jonathan E. Emmett

2
你可以将整个数组传递到钩子中,并将结果作为数组返回。你还应该使用useEffect处理异步逻辑。我重写了你的代码,一次处理所有3个字段: "最初的回答"
const useCableMatch = (searchInput) => {
  const [result, setResult] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [isError, setIsError] = useState(false);
  const client = useApolloClient();

  useEffect((searchInput) => {
     setIsError(false);
     setIsLoading(true);
     let response
     for(let field of searchInput){
        try {
           const { data } = await client.query({
              query: GET_VALID_CABLE,
              variables: { pn: `%${field}%` },
           });

           response = { ...data };
         } catch (error) {
             setIsError(true);
         }
     }
     setResult(current => {query, ...current, ...response);
     setIsLoading(false);
   };
  }, [searchInput])

  return [{ result, isLoading, isError }];
};

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接