根据文档:
当组件上方最近的
<MyContext.Provider>
更新时,此挂钩将触发重新渲染,并将最新的上下文值传递给该 MyContext 提供程序。即使祖先使用React.memo
或shouldComponentUpdate
,使用useContext从组件本身开始重新渲染仍然会发生。 ... 调用 useContext 的组件将始终在上下文值更改时重新呈现。
在我的Gatsby JS项目中,我这样定义我的上下文:
上下文.js
import React from "react"
const defaultContextValue = {
data: {
filterBy: 'year',
isOptionClicked: false,
filterValue: ''
},
set: () => {},
}
const Context = React.createContext(defaultContextValue)
class ContextProviderComponent extends React.Component {
constructor() {
super()
this.setData = this.setData.bind(this)
this.state = {
...defaultContextValue,
set: this.setData,
}
}
setData(newData) {
this.setState(state => ({
data: {
...state.data,
...newData,
},
}))
}
render() {
return <Context.Provider value={this.state}>{this.props.children}</Context.Provider>
}
}
export { Context as default, ContextProviderComponent }
在环绕多个组件的布局.js文件中,我放置了上下文提供程序:
布局.js:
import React from 'react'
import { ContextProviderComponent } from '../../context'
const Layout = ({children}) => {
return(
<React.Fragment>
<ContextProviderComponent>
{children}
</ContextProviderComponent>
</React.Fragment>
)
}
在我希望在其中使用上下文的组件中:
import React, { useContext } from 'react'
import Context from '../../../context'
const Visuals = () => {
const filterByYear = 'year'
const filterByTheme = 'theme'
const value = useContext(Context)
const { filterBy, isOptionClicked, filterValue } = value.data
const data = <<returns some data from backend>>
const works = filterBy === filterByYear ?
data.nodes.filter(node => node.year === filterValue)
:
data.nodes.filter(node => node.category === filterValue)
return (
<Layout noFooter="true">
<Context.Consumer>
{({ data, set }) => (
<div onClick={() => set( { filterBy: 'theme' })}>
{ data.filterBy === filterByYear ? <h1>Year</h1> : <h1>Theme</h1> }
</div>
)
</Context.Consumer>
</Layout>
)
Context.Consumer
正常工作,因为它成功地更新并反映了对上下文的更改。但是,如代码所示,我希望能够访问组件其他部分中更新的上下文值,即在专门使用Context.Consumer
的return
函数之外。我认为使用useContext
钩子会有所帮助,因为每次单击div 时,我的组件都会使用上下文中的新值重新渲染 - 但事实并非如此。任何帮助弄清楚为什么会这样,将不胜感激。
TL;DR:<Context.Consumer>
更新并反映子组件对上下文的更改,useContext
组件需要它,但不会。
更新:我现在已经发现useContext
将从传递给createContext
的默认上下文值中读取,并且基本上独立于Context.Provider
运行。这就是这里发生的事情,Context.Provider
包含一个修改状态的方法,而默认上下文值则不包含。我现在的挑战是找到一种方法,在默认上下文值中包含函数,该函数可以修改该值的其他属性。就目前而言:
const defaultContextValue = {
data: {
filterBy: 'year',
isOptionClicked: false,
filterValue: ''
},
set: () => {}
}
set
是一个在ContextProviderComponent
中定义的空函数(见上文(。我如何(如果可能(直接在上下文值中定义它,以便:
const defaultContextValue = {
data: {
filterBy: 'year',
isOptionClicked: false,
filterValue: ''
},
test: 'hi',
set: (newData) => {
//directly modify defaultContextValue.data with newData
}
}
没有必要同时使用<Context.Consumer>
和useContext
钩子。
通过使用useContext
钩子,您可以访问存储在上下文中的值。
对于特定示例,在视觉对象组件中使用上下文的更好方法如下:
import React, { useContext } from "react";
import Context from "./context";
const Visuals = () => {
const filterByYear = "year";
const filterByTheme = "theme";
const { data, set } = useContext(Context);
const { filterBy, isOptionClicked, filterValue } = data;
const works =
filterBy === filterByYear
? "filter nodes by year"
: "filter nodes by theme";
return (
<div noFooter="true">
<div>
{data.filterBy === filterByYear ? <h1>Year</h1> : <h1>Theme</h1>}
the value for the 'works' variable is: {works}
<button onClick={() => set({ filterBy: "theme" })}>
Filter by theme
</button>
<button onClick={() => set({ filterBy: "year" })}>
Filter by year
</button>
</div>
</div>
);
};
export default Visuals;
此外,您似乎没有在组件中使用works
变量,这可能是您无法获得所需结果的另一个原因。
您可以查看具有上述useContext
实现的工作示例,该示例与此沙盒中的示例有些相似
希望这有帮助。
问题非常简单 -<Visuals>
在组件树中比<Layout
更高,出于某种原因我仍在努力解决。将Itai的答案标记为正确,因为它最接近于弄清楚情况
除了Itai引用的解决方案之外,我相信我的问题可以帮助这里的其他人
就我而言,我发现了一些已经发生在我身上的事情,但现在出现了另一个症状,即不重新呈现依赖于上下文中存储的状态的视图。
这是因为主机和设备之间的日期存在差异。解释如下: https://github.com/facebook/react-native/issues/27008#issuecomment-592048282
这与我之前发现的另一个症状有关:https://stackoverflow.com/a/63800388/10947848
要解决此问题,只需按照第一个链接中的步骤操作,或者如果您发现有必要禁用调试模式