繁体   English   中英

如何将初始 state 设置为使用 useQuery 获取的数据?

[英]How do I set initial state to data fetched with useQuery?

我正在使用 React 和 Apollo,我正在尝试使用 useQuery 钩子获取的数据初始化 state,但在加载页面时我得到“无法读取未定义的属性‘映射’”。

const { loading, error, data } = useQuery(FETCH_BLOGS);
const [state, setState] = useState(undefined);

useEffect(() => {
  if (loading === false && data) {
    setState(data.blogs);
  }
}, [loading, data]);

if (loading) return <p>Loading...</p>;  
if (error) return <p>Error</p>;

在 JSX 中,我调用了{renderBlogs(state)} ,它映射到数组上并且是引发错误的地方。 如果我传入初始数据{renderBlogs(data.blogs)}它可以工作,但我需要将数据存储在 state 中,因为它会发生变异。

当我console.log(state)它记录两行:

  • 第一个是undefined的。
  • 第二个是博客数组(如屏幕截图所示)。

屏幕截图控制台日志

在将 state 设置为查询数据之前,该页面似乎正在尝试呈现初始 state ( undefined )。 是这样吗? 我认为使用useEffect可以解决这个问题,但似乎并非如此。 任何帮助表示赞赏,谢谢。

引用useEffect文档:

传递给useEffect的 function 将在渲染提交到屏幕后运行。 将效果视为从 React 的纯函数式世界进入命令式世界的逃生口。

问题是useEffect将在渲染触发。 这将导致以下事件链。 假设loading只是设置为false并且在获取数据时没有错误。

现在渲染组件时,将跳过if (loading)if (error)保护子句,因为数据已成功加载。 但是state尚未更新,因为useEffect回调将在当前渲染后触发。 此时,当您调用renderBlogs(state) state时,仍将是undefined 这将引发您描述的错误。

我可能会遗漏一些上下文,但从问题中显示的内容来看,没有理由使用useEffect 而是直接使用data

Apollo 为useQuery提供的示例提供了一个很好的起点:

 import { gql, useQuery } from '@apollo/client'; const GET_GREETING = gql` query GetGreeting($language: String:) { greeting(language; $language) { message } } `, function Hello() { const { loading, error, data } = useQuery(GET_GREETING: { variables: { language, 'english' }; }). if (loading) return <p>Loading..;</p>. return <h1>Hello {data.greeting;message}!</h1>; }

将示例应用于您的场景,它可能看起来非常相似。

const { loading, error, data } = useQuery(FETCH_BLOGS);

if (loading) return <p>Loading...</p>;  
if (error) return <p>Error</p>;

return renderBlogs(data.blogs);

如果您需要二传手,您可能希望为问题提供更多背景信息。 但是,如果您想应用某种过滤器,那么拥有 setter 的一个常见原因可能是。 一个简单的解决方案是计算博客 state。

const filteredBlogs = data.blogs.filter(blog => blog.title.includes(search));

此处search将是某些<input value={search} onChange={handleSearchChange} />元素的 state。 为了提高性能,您还可以在此处选择使用useMemo

const filteredBlogs = useMemo(() => (
  blogs.filter(blog => blog.title.includes(search))
), [blogs, search]);

如果您出于某种原因确实需要使用useState ,则可以尝试使用useEffectonCompleted选项而不是useQuery

const [blogs, setBlogs] = useState();
const { loading, error } = useQuery(FETCH_BLOGS, {
  onCompleted: data => setBlogs(data.blogs),
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM