如何使用 React 上下文 API?
Posted
技术标签:
【中文标题】如何使用 React 上下文 API?【英文标题】:How to use the React Context API? 【发布时间】:2019-12-15 12:51:11 【问题描述】:我有一个带有全局元素(自定义光标,即鼠标后的圆形 div)的 React 应用程序(使用 CRA 设置),当悬停不同嵌套的其他各种组件时,我想更新/更改其样式,或者不那么深入(在下面提供的结构中,我仅列出一个示例组件)。据我了解,这是 Context API 的一个很好的用例。
我的 App 的结构如下(简化):
<Cursor />
<Layout>
<Content>
<Item />
</Content>
</Layout>
所以当悬停<Item />
(在其他组件中)时,我想更新<Cursor />
组件的样式。
因此,我尝试访问我在 <Cursor />
组件中设置的函数,位于 <Item />
组件中。不幸的是,悬停时它不会更新我的状态,因此我的<Cursor />
的样式不会改变。
我的光标组件看起来像这样(简化):
import React, Component from "react"
export const CursorContext = React.createContext(false)
class Cursor extends Component
constructor(props)
super(props)
this.state =
positionX: 0,
positionY: 0,
scrollOffsetY: 0,
display: "none",
isHoveringProjectTeaserImage: false,
this.handleMousePosition = this.handleMousePosition.bind(this)
this.handleMouseOverProjectTeaser = this.handleMouseOverProjectTeaser.bind(this)
this.handleMouseLeaveProjectTeaser = this.handleMouseLeaveProjectTeaser.bind(this)
handleMousePosition = (mouse) =>
this.setState(
positionX: mouse.pageX,
positionY: mouse.pageY,
display: "block",
scrollOffsetY: window.pageYOffset
)
handleMouseOverProjectTeaser = () =>
this.setState(
isHoveringProjectTeaserImage: true
)
handleMouseLeaveProjectTeaser = () =>
this.setState(
isHoveringProjectTeaserImage: false
)
componentDidMount()
document.body.addEventListener("mousemove", this.handleMousePosition)
componentWillUnmount()
document.body.removeEventListener("mousemove", this.handleMousePosition)
render()
const
positionX,
positionY,
display,
scrollOffsetY,
isHoveringProjectTeaserImage
= this.state
return(
<CursorContext.Provider value=this.state>
<div>
<StyledCursor
style= isHoveringProjectTeaserImage
? backgroundColor: "red", display: `$display`, top: `$positionY - scrollOffsetYpx`, left: `$positionXpx`
: backgroundColor: "yellow", display: `$display`, top: `$positionY - scrollOffsetYpx`, left: `$positionXpx`
/>
</div>
</CursorContext.Provider>
)
export default Cursor
我的可以悬停的Item Component看起来像这样(简化):
import React, Component from "react"
import CursorContext from '../Cursor/Index';
class Item extends Component
constructor(props)
// not showing stuff in here that's not relevant
static contextType = CursorContext
render()
return(
<CursorContext.Consumer>
(value) =>
<StyledItem
onMouseOver=value.handleMouseOverProjectTeaser
onMouseLeave=value.handleMouseLeaveProjectTeaser
>
</StyledItem>
</CursorContext.Consumer>
)
export default Item
我还需要使用static contextType = CursorContext
吗?
当不传递默认值时(我认为它们无论如何都是可选的)我得到一个TypeError: Cannot read property 'handleMouseOverProjectTeaser' of undefined
,只要我传递一个很长的false
作为默认值,我的应用程序就会呈现但不会更新我的<Cursor />
状态。
我是否正确使用了 Context API?
【问题讨论】:
“当不传递默认值时”不确定这是指哪个部分 它是指拥有 React.createContext(false) 与拥有 React.createContext() 谢谢。赞成详细和集中的问题。 我在功能组件malikasinger.medium.com/…找到了这篇关于上下文API的文章 【参考方案1】:React.createContext 默认值?
正如您所说的那样,在这种情况下,传递给 React.createContext()
的值无关紧要。
当不传递默认值时(我认为它们无论如何都是可选的)我得到一个 TypeError: Cannot read property 'handleMouseOverProjectTeaser' of undefined, 只要我传递了一个很长的 false 作为默认值,我的应用程序就会呈现但没有更新我的状态。
这表明您的默认值始终被使用:尝试运行 undefined.blahblah
与 false.blahblah
:前者抛出 TypeError 而第二个静默返回 undefined
。
所以我们知道您在<Provider value=...>
中设置的值永远不会到达消费者,但是为什么?
上下文仅对其后代可用
<C.Consumer>
未呈现为<C.Provider>
的后代,因此无法访问它。换句话说,提供者应该“包围”消费者。来自文档:
上下文旨在共享可被视为 React 组件树“全局”的数据 [...]
那棵树的根是你的<C.Provider>
,在你的情况下,消费者不是那棵树的一部分。
类似的东西可以工作:
<CursorContext>
<StyledCursor />
<Layout>
<Content>
<Item />
</Content>
</Layout>
</CursorContext>
杂项
我什至需要使用静态 contextType = CursorContext 吗?
如果您使用的是<CursorContext.Consumer>
,则不是。来自文档:
Context.Consumer:订阅上下文更改的 React 组件。
但在您的情况下,由于您不需要监听上下文更改(无论如何都来自您的示例代码),只需保留 static contextType
:
static contextType = CursorContext
render()
return(
<StyledItem
onMouseOver=this.context.handleMouseOverProjectTeaser
onMouseLeave=this.context.handleMouseLeaveProjectTeaser
>
</StyledItem>
)
关键是你应该使用其中一个,你不需要两个。
最后一件事,您在提供程序中传递this.state
,并在子组件中使用this.context.handleMouseOverProjectTeaser
...但是<Cursor>
的状态中没有这样的功能。也许您打算传递 <Cursor>
本身,或者更好的是,只传递处理程序?
【讨论】:
感谢您非常详细且解释清楚的回答,非常感谢。老实说,我找不到时间尝试它,但会告诉你。再次感谢您! 这篇文章可能会有所帮助malikasinger.medium.com/…以上是关于如何使用 React 上下文 API?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 React v16.6 的新 CONTEXT API 中获取多个静态上下文
如何使用 React Context API 跨多个 Routes 拥有状态?
在组件之间路由时如何保持 React 新的 Context API 状态?
如何将 React Context API 与 useReducer 一起使用以遵循与 Redux 类似的风格 [关闭]