簡體   English   中英

React:在消費者中改變上下文

[英]React: Changing Context in Consumer

以下問題與 React Context 文檔中的以下部分有關:

  1. 動態上下文
  2. 從嵌套組件更新上下文

免責聲明:對以下所有背景信息深表歉意。 它提供了背景信息,希望對未來的訪問者有所幫助


我們所知道的

  • 鏈接 1
    • (默認)上下文值設置為themes.dark (一個包含兩個屬性的對象: foregroundbackground
    • 僅當組件樹中的Consumer上方沒有Providers時才使用默認值
    • 在這種情況下,頂級組件 ( App ) 中存在一個Provider
    • 這個Provider ( App ),將它自己的state作為上下文值傳遞下去
    • 保持Provider的值在結構和類型上與默認上下文值相同是明智的(避免Consumers感到困惑)
    • 因此,頂級組件 ( App ) 中的state持有與默認上下文值相同格式的對象: themes.light
    • 上面的結論:當Consumer讀取context 時,它讀取App的狀態
    • 換句話說,我們在這里使用上下文在組件樹的深處傳遞父( Appstate ,而不必通過中間的每個組件傳遞它
    • 當頂級組件 ( App ) 中的 state 發生變化時,它會重新渲染並將 state 的新值提供給Consumer
    • 這樣, Consumer通過上下文讀取父級的state
    • ...
    • 繼續前進,我們在鏈接 1 中看到設置state的函數( toggleTheme )作為普通prop向下傳遞到組件樹
    • 因此,在鏈接 1 中, context包含讀取state的對象
    • 我們能夠在設定狀態Consumer通過傳遞setState功能作為一個正常的propProvider的孩子,向下通過所有的中間組件,以及向Consumer
    • 在頂級組件 ( App ) 中設置state會導致自身重新呈現,從而導致重新呈現Provider ,然后將新的App state值通過上下文傳遞給它的Consumer
    • 因此, Consumer總是通過上下文知道App的狀態
    • 總之,流程是:
      1. state作為上下文值提供給子Consumer
      2. 某些孩子更新了父母的state
      3. 父級重新渲染
      4. Provider看到上下文值Appstate )已更改,並使用新值重新呈現其所有Consumer
  • 鏈接 2
    • 在鏈接 2 中,我們通過在上下文中傳遞setState函數來在Consumer設置state
    • 這與鏈接 1 不同,鏈接 1 中我們依靠普通prop來設置state

問題

我們從文檔中知道:

每個 Context 對象都帶有一個 Provider React 組件,該組件允許使用組件訂閱上下文更改......

每當 Provider 的 value 屬性發生變化時,所有作為 Provider 后代的消費者都會重新渲染。

  1. 假設我們在App使用一個普通變量作為上下文值 我們從上面的引用中知道,更改它會導致Provider重新渲染。 那么,我們為什么要費心使用state作為上下文值呢? 與僅在App使用任何普通變量相比,這樣做有什么好處?
  2. 以上兩種方法都允許我們更新state 為什么鏈接 2 包含state本身更新state的功能? 我們能否將它作為一個單獨的setState函數,通過具有兩個屬性(一個是state ,另一個是更新state的獨立函數)的對象中的上下文傳遞給Consumer

假設我們在 App 中使用一個普通變量作為上下文值。 我們從上面的引用中知道,更改它會導致 Provider 重新渲染。 那么,我們為什么要使用狀態作為上下文值呢? 與僅在 App 中使用任何普通變量相比,這樣做有什么好處?

確實,當使用更改的值重新呈現提供者時,任何關心上下文的后代都會重新呈現。 但是您首先需要一些東西來使提供者重新呈現。 當 App 的 state 或其 props 發生變化時(或者當你調用 forceUpdate,但不要那樣做)時,就會發生這種情況。 據推測,這是在您的應用程序的頂部,所以沒有道具進來,這意味着您將使用 state 使其重新渲染。

上述兩種方法都允許我們更新狀態。 為什么鏈接 2 包含在狀態本身內更新狀態的功能? 我們能否將它作為一個單獨的 setState 函數,通過具有兩個屬性(一個是狀態,另一個是更新狀態的獨立函數)的對象中的上下文傳遞給消費者?

當決定是否由於上下文的變化而重新渲染后代時,react 基本上會在舊值和新值之間做一個=== 這非常快,並且適用於 React 對不可變數據的偏好,但是當使用對象作為您的值時,您需要小心不要在每次渲染時都創建新對象。 例如,如果 App 正在做類似下面的事情,它會在每次渲染時創建一個全新的對象,因此將強制所有上下文消費者也重新渲染:

class App extends Component {
  state = {
    data: { 
      hello: 'world',
    }
  }

  updateData() {
    // some function for updating the state  
  }

  render() {
    return (
      <MyContext.Provider value={{ 
        data: this.state.data, 
        updateData: this.updateData
      }} />
    )
  }
}

因此,他們將函數存儲在狀態中的示例是確保他們提供的整個值不會從一個渲染更改為另一個渲染。

假設我們在 App 中使用一個普通變量作為上下文值。 我們從上面的引用中知道,更改它會導致 Provider 重新渲染。 那么,我們為什么要使用狀態作為上下文值呢? 與僅在 App 中使用任何普通變量相比,這樣做有什么好處?

當你使用 state 並更新它時——不管你是否使用提供者——所有的提供者和它下面的組件都會更新。 那是在官方 React Context 文檔下,是錯誤的。 這意味着更改提供者值根本不會調用消費者更新。

您可以通過創建一個帶有狀態的單獨組件(不會在提供者內部)來驗證這一點,並將該狀態變量分配給提供者。 因此,當組件狀態發生變化時,狀態中的值發生變化,提供者應該注意到這一點並更新消費者。 它沒有做。

不幸的是,為了更新消費者下的組件,您必須手動進行。 除非您的意圖是更新提供程序下的所有內容。

在 React 17.0.2 下,截至 2021 年 4 月 21 日,情況確實如此——提供者值的變化沒有被監控,消費者也沒有被更新。 除非您將所有提供程序都放在帶有狀態的組件中,但更改其狀態會強制更新提供程序下的所有組件。 可悲。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM