反应:改变消费者的环境

时间:2019-03-26 19:02:43

标签: javascript reactjs

以下问题与React Context文档中的以下部分相关:

  1. Dynamic Context
  2. Updating Context from a Nested Component

免责声明:对以下所有背景信息深表歉意。它提供了背景信息,希望对以后的访问者有帮助。


我们所知道的

  • 链接1
    • (默认)上下文值设置为themes.dark(一个包含两个属性的对象:foregroundbackground
    • 仅当组件树中Providers上方没有Consumer时才使用默认值
    • 在这种情况下,顶级组件(Provider)中存在App
    • ProviderApp)作为{em> context值
    • 传递自己的state
    • Provider提供的值的结构和类型设置为默认的 context值(避免Consumers混淆)是很聪明的
    • 因此,顶级组件(state)中的App拥有与默认 context值相同的格式的对象:themes.light
    • 以上结论:当Consumer读取上下文时,它将读取App的状态
    • 换句话说,我们在这里使用 context 在组件树的深处传递父级(Appstate,而不必将其传递给每个组件在中间
    • 顶级组件(App)中的状态更改时,它会重新呈现,并为Consumer提供新的状态值
    • 通过这种方式,Consumer通过 context
    • 读取父级的state
    • ...
    • 继续,我们在链接1中看到将 set statetoggleTheme)的功能作为普通prop传递到组件树中/ li>
    • 因此,在链接1中,context 包含读取 state
    • 的对象
    • 我们可以通过将Consumer的子元素作为普通setState传递prop函数,在Provider中设置状态{em> ,向下遍历所有中间组件,然后进入Consumer
    • 在顶级组件(state)中设置App会导致自身的重新呈现,这会导致Provider的重新呈现通过 context
    • 将新的App state值向下传递到其Consumer
    • 这样,Consumer总是通过 context
    • 知道App的状态。
    • 总而言之,流程为:
      1. 父母的state作为上下文值提供给孩子Consumer
      2. 父母的state由某个孩子更新
      3. 家长重新渲染
      4. Provider看到 context值App的{​​{1}})已更改,并使用新价值
  • 链接2
    • 在链接2中,通过在 context 中传递state函数,在Consumer中设置{em> {} {em} li>
    • 这与链接1不同,在链接1中,我们依靠普通的state来设置Consumer

问题

我们从the docs知道:

  

每个Context对象都带有一个提供方React组件,该组件允许   消耗组件以订阅上下文更改。...

     

作为提供者后代的所有使用者将重新呈现   只要提供商的价值支柱发生变化。

  1. 假设我们在setState中使用普通变量作为上下文值。从上面的引用中我们知道,更改它会导致prop重新呈现。那么,为什么要使用state作为 context 值呢?与仅在App中使用任何普通变量相比,这样做有什么好处?
  2. 以上两种方法均允许我们更新Provider。为什么链接2合并了在state内更新App 的功能?我们不能仅仅将其作为单独的state函数,它通过 context 传递给具有两个属性(一个是state)的对象中的state另一个是独立功能来更新setState)?

2 个答案:

答案 0 :(得分:2)

  

让我们假设我们在App中使用普通变量作为上下文值。从上面的引用我们知道,更改它会导致提供程序重新渲染。那么,为什么要麻烦使用状态作为上下文值呢?与仅在App中使用任何普通变量相比,这样做有什么好处?

的确,当使用更改的值重新提供提供程序时,所有关心上下文的后代都将重新提交。但是您首先需要使提供者重新呈现的内容。当App的状态或其属性发生更改时(或当您调用forceUpdate而不执行此操作时),就会发生这种情况。大概,这是在应用程序的顶部,因此没有任何道具进入,这意味着您将使用状态来使其重新呈现。

  

以上两种方法都允许我们更新状态。为什么链接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
      }} />
    )
  }
}

因此,他们在状态中存储函数的示例是确保所提供的整个值不会从一个渲染更改为另一个。

答案 1 :(得分:0)

<块引用>

假设我们使用 App 中的一个普通变量作为上下文值。我们从上面的引用中知道,更改它会导致 Provider 重新渲染。那么,我们为什么要使用状态作为上下文值呢?与仅在 App 中使用任何普通变量相比,这样做有什么好处?

当你使用 state 并更新它时——不管你是否使用提供者——所有的提供者和它下面的组件都会更新。那是在官方 React Context 文档下,是错误的。这意味着更改提供者值根本不会调用使用者更新。

您可以通过创建一个带有状态的单独组件(不会在提供者内部)来验证这一点,并将该状态变量分配给提供者。因此,当组件状态发生变化时,状态中的值发生变化,提供者应该注意到这一点并更新消费者。它没有这样做。

为了更新消费者下的组件,不幸的是,您必须手动进行。除非您打算更新提供程序下的所有内容。

截至 2021 年 4 月 21 日,在 React 17.0.2 下这是真的——提供者值的变化没有被监控,消费者也没有被更新。除非您将所有提供程序都放在带有状态的组件中,但更改其状态会强制更新提供程序下的所有组件。很遗憾。