无法将反应查询结果传递到子组件中

bln*_*nks 1 javascript reactjs next.js react-query

在我的第一个Next.js项目中,我有一个在服务器端呈现的文章组件。我想从客户端获取文章标签,否则我会得到太多 DOM 元素。所以这就是我想出的:

const ArticlesPage = () => {    

    const [tags, setTags] = useState([])
    const   { isLoading, isError, data, error } = useQuery('tags', getTags, {
        onSuccess: () => setTags(data)
       }
       //...
    })
    console.log('tags are:', tags)
     return ( 
        <>
              ...
              {!isLoading && !isError &&
            <TagsComponent tags={tags} />
            
              }
              
               {isLoading && 
                 <div> Loading tags...</div>            
              }
              
              {isError && 
                 <div> Error fetching tags</div>            
              }     
         
        </>
Run Code Online (Sandbox Code Playgroud)

问题是标签异想天开地呈现在文章页面上,也就是说,当我刷新页面时,它们不会显示,但当我重新关注页面时,标签会显示。我也没有看到任何LoadingError正在渲染。所以我很困惑这里发生了什么?

我怎样才能解决这个问题?

Cha*_* S. 5

正如另一个答案中提到的,您不应该使用 setState 来存储从 API 返回的数据。这样做将使您的缓存管理非常难以维护和推理。相反,您应该使用状态来存储结果的筛选选项,然后使用该状态来筛选数据。

如果您的 API 支持过滤

假设您的 API 使用有效负载来过滤响应,我们可以将要发送的有效负载存储在“过滤器”状态变量中,并将其用作我们的查询密钥。

它们的关键函数getTags应该接受{queryKey: [,filter]}作为其参数,并且应该将过滤器传递给 api 调用。filter然后你可以通过和属性在 TagsComponent 中控制它setFilter

const ArticlesPage = () => {
  const [filter, setFilter] = useState({});

  const { isLoading, isError, data: tags, error } = useQuery(
    ["tags", filter], 
    getTags,
  );

  console.log("tags are:", tags);

  if(isError) return <div>Error fetching tags</div>;

  if(isLoading) return <div>Loading tags...</div>;

  return <TagsComponent 
           tags={tags} 
           filter={filter} 
           setFilter={setFilter} />;
};
Run Code Online (Sandbox Code Playgroud)

如果您在本地过滤结果

由于您不能依赖 API 来过滤结果,因此您需要在响应返回后过滤结果。再次假设您有filter用户指定的某种状态,以及一个filterTags(filter, tags) => filteredTags根据该状态过滤标签的函数,我们可以通过以下方式将它们组合在一起:

const ArticlesPage = () => {
  const [filter, setFilter] = useState({});

  const { isLoading, isError, data: tags, error } = useQuery("tags", getTags);

  const filteredTags = useMemo(() => filterTags(filter, tags), [tags, filter]);

  if(isError) return <div>Error fetching tags</div>;

  if(isLoading) return <div>Loading tags...</div>;

  return <TagsComponent 
           tags={filteredTags} 
           filter={filter} 
           setFilter={setFilter} />;
};
Run Code Online (Sandbox Code Playgroud)