我有一个带有全局元素(自定义光标,即鼠标后面的圆形div)的React应用程序(使用CRA设置),当悬停不同嵌套的各种其他组件时,我想更新/更改其样式不太深入(在下面提供的结构中,我只列出了一个示例组件)。据我了解,这是 Context API 的一个很好的用例。
我的应用程序的结构如下所示(简化):
<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 - scrollOffsetY}px`, left: `${positionX}px`}
: {backgroundColor: "yellow", display: `${display}`, top: `${positionY - scrollOffsetY}px`, left: `${positionX}px`}}
/>
</div>
</CursorContext.Provider>
)
}
}
export default Cursor
我的可以悬停的项目组件看起来像这样(简化):
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默认值?
正如您正确所述,值传递给 React.createContext()
在这种情况下并不重要。
When not passing a default value (I thought they are optional anyway) I am getting an TypeError: Cannot read property 'handleMouseOverProjectTeaser' of undefined, as soon as I pass a long a false as default value my App renders but does not update my state.
这表明始终使用您的默认值:尝试运行 undefined.blahblah
与 false.blahblah
:前者抛出 TypeError 而第二个默默返回 undefined
.
所以我们知道您在 <Provider value={...}>
中设置的值永远不会到达消费者手中,但是为什么?
上下文仅对其后代可用
<C.Consumer>
不呈现为 <C.Provider>
的后代,所以它无法访问它。换句话说,供应商应该“包围”消费者。来自文档:
Context is designed to share data that can be considered “global” for a tree of React components [...]
那棵树的根是你的<C.Provider>
,在您的情况下,消费者不是该树的一部分。
类似的东西可以工作:
<CursorContext>
<StyledCursor />
<Layout>
<Content>
<Item />
</Content>
</Layout>
</CursorContext>
其他
Do I even need to use static contextType = CursorContext?
并非如此,如果您使用 <CursorContext.Consumer>
。来自文档:
Context.Consumer: A React component that subscribes to context changes.
但就您而言,由于您不需要监听上下文更改(无论如何都来自您的示例代码),因此只需保留 static contextType
:
static contextType = CursorContext
render() {
return(
<StyledItem
onMouseOver={this.context.handleMouseOverProjectTeaser}
onMouseLeave={this.context.handleMouseLeaveProjectTeaser}
>
</StyledItem>
)
}
重点是您应该使用其中之一,您不需要两者都需要。
最后一件事,你即将通过 this.state
在提供者中,并使用 this.context.handleMouseOverProjectTeaser
在子组件中...但是<Cursor>
中没有这样的功能的状态。也许您打算通过 <Cursor>
本身,或者更好,只是处理程序?
关于reactjs - 如何使用 React Context API?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57401934/