reactjs - 如何使用 React Context API?

标签 reactjs react-context

我有一个带有全局元素(自定义光标,即鼠标后面的圆形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.blahblahfalse.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/

相关文章:

reactjs - antd表中使用rowSelection在父行上select时选择子行

reactjs - 如何在提供者(React、Typescript、Context)的值中传递数组和 setArray

reactjs - React - 类内的useContext

javascript - 如何输入接受具有超属性集的 Context 的 Typescript React 组件

javascript - react 上下文不更新

javascript - 如何将大量视频文件导入 React 应用程序

javascript - React Material UI ListItem 单击

javascript - 如何通过从 api 获取值来填充 react 选择的选项,以便在单击选择框时可见?

Reactjs 路由导致页面渲染问题

javascript - react 值返回为未定义