欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ReactQuery?渲染優(yōu)化示例詳解

 更新時間:2022年11月10日 11:16:25   作者:lakb248  
這篇文章主要為大家介紹了ReactQuery?渲染優(yōu)化示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

引言

免責聲明:渲染優(yōu)化是所有應用的進階話題。React Query已經進行了許多性能優(yōu)化并且開箱即用,大多數時候不需要做更多優(yōu)化。"不必要的重新渲染"是一個很多人投入大量關注的話題,也是我要寫這篇文章的原因。但是我要再一次指出,大部分情況下對于大多數應用來說,渲染優(yōu)化很可能并沒有想得那么重要。重新渲染是一個好事情。它保證了你的應用展示了最新的狀態(tài)。相比于重復渲染,我更關注由于缺少渲染而導致的渲染錯誤。對于更多關于這個話題的討論,可以看下面的內容:

我在第二篇文章介紹select的內容中已經講了一些關于渲染優(yōu)化的事情。然而,"為什么在沒有任何數據變化的情況下,React Query會渲染兩次組件呢"是我平時被問到最多的一個問題。我們讓我來嘗試深入解釋一下。

isFetching

在之前的例子中我說過,下面這個組件只會在todos的length變化時才會重新渲染,其實我只說了一部分事實:

export const useTodosQuery = (select) =>
  useQuery(['todos'], fetchTodos, { select })
export const useTodosCount = () => useTodosQuery((data) => data.length)
function TodosCount() {
  const todosCount = useTodosCount()
  return <div>{todosCount.data}</div>
}

每次發(fā)生后臺refetch的時候,這個組件都會下面的數據分別進行一次渲染:

{ status: 'success', data: 2, isFetching: true }
{ status: 'success', data: 2, isFetching: false }

這是因為React Query在每個查詢中返回了很多基本信息,isFetching就是其中一個。這個屬性在請求正在發(fā)生的時候會被設置為true。這個在你想要展示一個后臺請求的loading標志的時候特別有用。但是如果你不需要,那確實會造成一些不必要的渲染。

notifiOnChange

對于上面說到的這個場景,React Query提供了notifyOnChangeProps參數。他可以在每個場景單獨設置來告訴React Query:只在這些屬性發(fā)生變化的時候再通知我。通過將這個參數設置為['data'],我們可以實現一個新的版本:

export const useTodosQuery = (select, notifyOnChangeProps) =>
  useQuery(['todos'], fetchTodos, { select, notifyOnChangeProps })
export const useTodosCount = () =>
  useTodosQuery((data) => data.length, ['data'])

保持同步

盡管上面的代碼可以正常工作,但是它很容易就會造成不同步。如果我們希望針對error進行特殊處理呢?又或者我們需要使用isLoading屬性呢?我們不得不確保notifyOnChangeProps屬性和我們實際用到的數據保持同步。如果我們忘記將某個數據添加到屬性里面,而只監(jiān)聽data屬性的變化,當查詢返回錯誤,同時我們也要展示這些錯誤的時候,我們的組件并不會重新渲染。這個問題當我們把這些屬性寫死在自定義hook的時候格外明顯,因為我們并不知道使用自定義hook的組件實際上會用到哪些數據:

export const useTodosCount = () =>
  useTodosQuery((data) => data.length, ['data'])
function TodosCount() {
  // ?? we are using error, but we are not getting notified if error changes!
  const { error, data } = useTodosCount()
  return (
    <div>
      {error ? error : null}
      {data ? data : null}
    </div>
  )
}

就像我在文章開頭免責聲明中說的,我認為這是比偶爾發(fā)生的不必要的重新渲染更壞的事情。當然,我們可以傳參數給自定義hook,但是這還是需要手動處理,是否有什么方式可以自動處理這個情況呢?請看:

被追蹤的查詢

這是我感受特別自豪的一個特性,這也是我對這個庫第一個重大的貢獻。如果你將notifyOnChangeProps設置為'tracked',React Query會跟蹤你在渲染過程中用到的數據,會自動計算依賴列表。最終的效果就跟你手動維護這個列表一樣,除了你不用再去關注這個問題以外。你也可以全局開啟這個特性:

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      notifyOnChangeProps: 'tracked',
    },
  },
})
function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Example />
    </QueryClientProvider>
  )
}

利用這個特性,你再也不用考慮重新渲染。當然這個特性也有一些限制,這就是為什么這個特性是一個可選項:

如果你使用對象剩余屬性結構的語法的話,最終所有屬性都會被追蹤。正常的解構語法是沒問題的,不要這么做:

// ?? will track all fields
const { isLoading, ...queryInfo } = useQuery(...)
// ? this is totally fine
const { isLoading, data } = useQuery(...)

被追蹤的查詢只會追蹤render過程中用到的數據。如果你只在effects中用到了這些數據,他們并不會被追蹤。

const queryInfo = useQuery(...)
// ?? will not corectly track data
React.useEffect(() => {
  console.log(queryInfo.data)
})
// ? fine because the dependency array is accessed during render
React.useEffect(() => {
  console.log(queryInfo.data)
}, [queryInfo.data])

被追蹤的查詢不會在每次render的時候被重置,所以只要你使用了一次某個數據,你就會在整個組件的生命周期內追蹤這個數據:

const queryInfo = useQuery(...)
if (someCondition()) {
  // ?? we will track the data field if someCondition was true in any previous render cycle
  return <div>{queryInfo.data}</div>
}

結構化共享

一個不同的但是并沒那么重要的React Query默認開啟的渲染優(yōu)化是結構化共享。這個特性確保數據在所有地方是引用唯一的。舉個例子,假設我們有下面這個數據結構:

[
{ "id": 1, "name": "Learn React", "status": "active" },
{ "id": 2, "name": "Learn React Query", "status": "todo" }
]

現在假設我們將第一個todo轉為done,然后進行了一次后臺refetch。我們會從后端拿到一個全新的json:

{ "id": 1, "name": "Learn React", "status": "active" },
{ "id": 1, "name": "Learn React", "status": "done" },
{ "id": 2, "name": "Learn React Query", "status": "todo" }
]

現在React Query會嘗試對比新老狀態(tài),盡可能多的復用老的狀態(tài)。在上面的例子中,todo數據會是一個新的對象,因為我們更新了一個todo。第一個id為1的對象也會是新的對象,但是對于id為2的對象我們會保持跟對應的舊數據一樣的引用-React Query會將他復制一份同樣的引用到新的數據,因為這部分數據并沒有發(fā)生變化。

這使得使用selector進行部分訂閱變得特別友好:

// ? will only re-render if something within todo with id:2 changes
// thanks to structural sharing
const { data } = useTodo(2)

就像我之前提到的,對于selector來說結構化共享會用到兩次:一次是在queryFn返回的結果上,另一次是在selector返回的結果上。在一些場景,特別是數據量比較大的場景,結構化共享會成為一個瓶頸。同時它只能使用在JSON可序列化的數據上。如果你不需要這個優(yōu)化,你可以通過將`structuralSharing`設為false來關閉這個特性。

以上就是ReactQuery 渲染優(yōu)化示例詳解的詳細內容,更多關于ReactQuery 渲染優(yōu)化的資料請關注腳本之家其它相關文章!

相關文章

  • React組件與事件的創(chuàng)建使用教程

    React組件與事件的創(chuàng)建使用教程

    react事件綁定時。this并不會指向當前DOM元素。往往使用bind來改變this指向,今天通過本文給大家介紹React事件綁定的方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧
    2023-02-02
  • react如何向數組中追加值

    react如何向數組中追加值

    這篇文章主要介紹了react如何向數組中追加值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 基于React.js實現兔兔牌九宮格翻牌抽獎組件

    基于React.js實現兔兔牌九宮格翻牌抽獎組件

    這篇文章主要為大家詳細介紹了如何基于React.js實現兔兔牌九宮格翻牌抽獎組件,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2023-01-01
  • React事件監(jiān)聽和State狀態(tài)修改方式

    React事件監(jiān)聽和State狀態(tài)修改方式

    這篇文章主要介紹了React事件監(jiān)聽和State狀態(tài)修改方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • react數據管理中的setState與Props詳解

    react數據管理中的setState與Props詳解

    setState?是?React?中用于更新組件狀態(tài)(state)的方法,本文給大家介紹react數據管理中的setState與Props知識,感興趣的朋友跟隨小編一起看看吧
    2023-10-10
  • React如何使用sortablejs實現拖拽排序

    React如何使用sortablejs實現拖拽排序

    這篇文章主要介紹了React如何使用sortablejs實現拖拽排序問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • create-react-app項目配置全解析

    create-react-app項目配置全解析

    這篇文章主要為大家介紹了create-react-app項目配置全解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • React利用路由實現登錄界面的跳轉

    React利用路由實現登錄界面的跳轉

    這篇文章主要介紹了React利用路由實現登錄界面的跳轉,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • react實現全局組件確認彈窗

    react實現全局組件確認彈窗

    這篇文章主要為大家詳細介紹了react實現全局組件確認彈窗,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • 解決React報錯No duplicate props allowed

    解決React報錯No duplicate props allowed

    這篇文章主要為大家介紹了React報錯No duplicate props allowed解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12

最新評論