[英]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
,则可以尝试使用useEffect
的onCompleted
选项而不是useQuery
。
const [blogs, setBlogs] = useState();
const { loading, error } = useQuery(FETCH_BLOGS, {
onCompleted: data => setBlogs(data.blogs),
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.