[英]React: Changing Context in Consumer
The below question relates to the following sections in the React Context documentation:以下问题与 React Context 文档中的以下部分有关:
Disclaimer: Apologies for all the background information below.免责声明:对以下所有背景信息深表歉意。 It provides context and will hopefully be helpful to future visitors .
它提供了背景信息,希望对未来的访问者有所帮助。
What We Know我们所知道的
themes.dark
(an object that contains two properties: foreground
and background
) themes.dark
(一个包含两个属性的对象: foreground
和background
)Providers
above the Consumer
in the component treeConsumer
上方没有Providers
时才使用默认值Provider
present in the top-level component ( App
)App
) 中存在一个Provider
Provider
( App
), passes down its own state
as the context valueProvider
( App
),将它自己的state
作为上下文值传递下去Provider
equal in structure and type to the default context value (avoids Consumers
getting confused)Provider
的值在结构和类型上与默认上下文值相同是明智的(避免Consumers
感到困惑)state
in the top-level component ( App
) holds an object of the same format as the default context value : themes.light
App
) 中的state
持有与默认上下文值相同格式的对象: themes.light
Consumer
reads the context , it reads App
's stateConsumer
读取context 时,它读取App
的状态App
) state
deep down in the component tree, without having to pass it through every component in the middleApp
) state
,而不必通过中间的每个组件传递它App
) changes, it re-renders and a new value for state is provided to the Consumer
App
) 中的 state 发生变化时,它会重新渲染并将 state 的新值提供给Consumer
Consumer
reads the parent's state
, via contextConsumer
通过上下文读取父级的state
state
( toggleTheme
) is passed down the component tree as a normal prop
state
的函数( toggleTheme
)作为普通prop
向下传递到组件树context
only contains an object that reads state
context
仅包含读取state
的对象Consumer
by passing the setState
function as a normal prop
from the Provider
's child, down through all the intermediate components, and in to the Consumer
Consumer
通过传递setState
功能作为一个正常的prop
从Provider
的孩子,向下通过所有的中间组件,以及向Consumer
state
in the top-level component ( App
), leads to a re-render of itself, which leads to a re-render of the Provider
, which then passes the new App
state
value down to its Consumer
via contextApp
) 中设置state
会导致自身重新呈现,从而导致重新呈现Provider
,然后将新的App
state
值通过上下文传递给它的Consumer
Consumer
always knows App
's state, via contextConsumer
总是通过上下文知道App
的状态state
is provided as context value to child Consumer
(s)state
作为上下文值提供给子Consumer
state
is updated by some childstate
Provider
sees that context value ( App
's state
) has changed, and re-renders all its Consumer
s with the new value Provider
看到上下文值( App
的state
)已更改,并使用新值重新呈现其所有Consumer
。state
in the Consumer
, by passing the setState
function within the contextsetState
函数来在Consumer
设置state
prop
to set state
prop
来设置state
Questions问题
We know from the docs that:我们从文档中知道:
Every Context object comes with a Provider React component that allows consuming components to subscribe to context changes....
每个 Context 对象都带有一个 Provider React 组件,该组件允许使用组件订阅上下文更改......
All consumers that are descendants of a Provider will re-render whenever the Provider's value prop changes.
每当 Provider 的 value 属性发生变化时,所有作为 Provider 后代的消费者都会重新渲染。
App
as the context value .App
使用一个普通变量作为上下文值。 We know from the above quote that changing it leads to the Provider
re-rendering.Provider
重新渲染。 Why then, do we bother using state
as the context value?state
作为上下文值呢? What is the benefit of that, vs. just using any normal variable in App
?App
使用任何普通变量相比,这样做有什么好处?state
.state
。 Why is link 2 incorporating the function to update state
within state
itself?state
本身内更新state
的功能? Could we not just have it as a separate setState
function, which is passed to the Consumer
via context in an object that has two properties (one is state
and the other is the standalone function to update state
)?setState
函数,通过具有两个属性(一个是state
,另一个是更新state
的独立函数)的对象中的上下文传递给Consumer
?Let's assume we use a normal variable in App as the context value.
假设我们在 App 中使用一个普通变量作为上下文值。 We know from the above quote that changing it leads to the Provider re-rendering.
我们从上面的引用中知道,更改它会导致 Provider 重新渲染。 Why then, do we bother using state as the context value?
那么,我们为什么要使用状态作为上下文值呢? What is the benefit of that, vs. just using any normal variable in App?
与仅在 App 中使用任何普通变量相比,这样做有什么好处?
It's true that when the provider is rerendered with a changed value, any descendents that care about the context will rerender.确实,当使用更改的值重新呈现提供者时,任何关心上下文的后代都会重新呈现。 But you need something to cause the provider to rerender in the first place.
但是您首先需要一些东西来使提供者重新呈现。 This will happen when App's state or its props change (or when you call forceUpdate, but don't do that).
当 App 的 state 或其 props 发生变化时(或者当你调用 forceUpdate,但不要那样做)时,就会发生这种情况。 Presumably, this is at the top of your application, so there are no props coming in, which means you'll use state to cause it to rerender.
据推测,这是在您的应用程序的顶部,所以没有道具进来,这意味着您将使用 state 使其重新渲染。
Both the two approaches above allow us to update state.
上述两种方法都允许我们更新状态。 Why is link 2 incorporating the function to update state within state itself?
为什么链接 2 包含在状态本身内更新状态的功能? Could we not just have it as a separate setState function, which is passed to the Consumer via context in an object that has two properties (one is state and the other is the standalone function to update state)?
我们能否将它作为一个单独的 setState 函数,通过具有两个属性(一个是状态,另一个是更新状态的独立函数)的对象中的上下文传递给消费者?
When deciding whether to rerender descendants due to a change of context, react will do basically a ===
between the old value and the new value.当决定是否由于上下文的变化而重新渲染后代时,react 基本上会在旧值和新值之间做一个
===
。 This is super quick and works well with React's preference for immutable data, but when using objects as your value you need to be careful that you're not making new objects on every render.这非常快,并且适用于 React 对不可变数据的偏好,但是当使用对象作为您的值时,您需要小心不要在每次渲染时都创建新对象。 For example, if App is doing something like the following, it will be creating a brand new object every time it renders, and thus will be forcing all the context consumers to rerender as well:
例如,如果 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
}} />
)
}
}
So the example where they store the function in state is to make sure that the entire value they're providing does not change from one render to another.因此,他们将函数存储在状态中的示例是确保他们提供的整个值不会从一个渲染更改为另一个渲染。
Let's assume we use a normal variable in App as the context value.
假设我们在 App 中使用一个普通变量作为上下文值。 We know from the above quote that changing it leads to the Provider re-rendering.
我们从上面的引用中知道,更改它会导致 Provider 重新渲染。 Why then, do we bother using state as the context value?
那么,我们为什么要使用状态作为上下文值呢? What is the benefit of that, vs. just using any normal variable in App?
与仅在 App 中使用任何普通变量相比,这样做有什么好处?
When you use state and update it - it does not matter at all if you are using provider or not - all the provider and components under it will update.当你使用 state 并更新它时——不管你是否使用提供者——所有的提供者和它下面的组件都会更新。 Thats under official React Context documentation and is wrong.
那是在官方 React Context 文档下,是错误的。 It means changing provider values DOES NOT call consumer updates at all.
这意味着更改提供者值根本不会调用消费者更新。
You can validate this by making a separate component with state (which would not be inside provider) and assign that state variable to the provider.您可以通过创建一个带有状态的单独组件(不会在提供者内部)来验证这一点,并将该状态变量分配给提供者。 So when component state changes, value in state changes and in turn provider should notice this and update consumer.
因此,当组件状态发生变化时,状态中的值发生变化,提供者应该注意到这一点并更新消费者。 Which it is NOT doing.
它没有做。
In order to update components under consumers, you, unfortunately, have to do it manually.不幸的是,为了更新消费者下的组件,您必须手动进行。 Unless your intension is to update everything under the provider.
除非您的意图是更新提供程序下的所有内容。
This is true as of 2021-04-21 under React 17.0.2 - provider value changes are not being monitored and consumers are not being updated sadly.在 React 17.0.2 下,截至 2021 年 4 月 21 日,情况确实如此——提供者值的变化没有被监控,消费者也没有被更新。 Unless you put all your provider in component with state, but changing its state forces updating all components under the provider.
除非您将所有提供程序都放在带有状态的组件中,但更改其状态会强制更新提供程序下的所有组件。 Sadly.
可悲。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.