簡體   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