【问题标题】:Accessing context values outside of Context.Consumer在 Context.Consumer 之外访问上下文值
【发布时间】:2019-11-28 18:35:28
【问题描述】:

我正在尝试在我的样式化组件中访问 ThemeContext.Consumer 的值。我正在使用 Gatsby 来实现暗模式。

这是ThemeContext.Consumer 文件:

import React from 'react'

const defaultState = {
  dark: false,
  toggleDark: () => {},
}
const ThemeContext = React.createContext(defaultState)
// Getting dark mode information from OS!
// You need macOS Mojave + Safari Technology Preview Release 68 to test this currently.
const supportsDarkMode = () =>
  window.matchMedia('(prefers-color-scheme: dark)').matches === true
class ThemeProvider extends React.Component {
  state = {
    dark: false,
  }

  componentDidMount() {
    // Getting dark mode value from localStorage!
    const lsDark = JSON.parse(localStorage.getItem('dark'))
    if (lsDark) {
      this.setState({ dark: lsDark })
    } else if (supportsDarkMode()) {
      this.setState({ dark: true })
    }
  }

  // https://stackoverflow.com/questions/59005886/eslint-prevent-using-this-state-within-a-this-setstate-react-no-access-state-i?stw=2
  toggleDark = () => {
    const dark = !this.state.dark
    localStorage.setItem('dark', JSON.stringify(dark))
    this.setState(({ dark }) => ({ dark: !dark }))
  }

  render() {
    const { children } = this.props
    const { dark } = this.state
    return (
      <ThemeContext.Provider
        value={{
          dark,
          toggleDark: this.toggleDark,
        }}
      >
        {children}
      </ThemeContext.Provider>
    )
  }
}
export default ThemeContext
export { ThemeProvider }

这是我的Header.js file

import React from 'react'
import styled from 'styled-components'

import ThemeContext from '../context/ThemeContext'

class Header extends React.Component {
  render() {
    const currentTheme = this.props.theme

    return (
      <ThemeContext.Consumer>
        {theme => (
          <HeaderWrapper>
            <span
              role="presentation"
              className="dark-switcher"
              onClick={theme.toggleDark}
            >
              {theme.dark ? <span>☀</span> : <span>☾</span>}
            </span>
          </HeaderWrapper>
        )}
      </ThemeContext.Consumer>
    )
  }
}

export default Header

const HeaderWrapper = styled.div`
  background: ${() => (theme.dark ? '#C6D0EB' : '#205284')};
  border-bottom: 1px solid var(--accents-2);
`

我添加了const currentTheme = this.props.theme 以便能够在全局范围内使用该值。希望能够在我的样式化组件中使用它。

关于如何解决这个问题的任何建议?

【问题讨论】:

  • 您的实际问题是什么?我猜它的背景颜色没有改变?如果是这样,您应该将其写在您的问题中。此外,您的HeaderWrapper 无权访问theme。如果需要,将其作为道具显式传递。也许将所有这些都放在 CodeSandBox.io 中,这样我们就可以轻松地检查和帮助:)
  • 您能说明ThemeProvider 的确切使用位置吗?
  • 这里是 CodeSandbox 的链接 - codesandbox.io/s/github/laurosilvacom/laurosilvacom。我正在尝试从我的样式组件内部访问theme.dark。而不是添加另一个类(正如您从 Codesandbox 存储库中看到的那样)。如何将“主题”明确作为道具传递?抄送:@PowellYe @antoine129
  • 谢谢劳罗,我相信我知道解决方案,稍后会给出答案。

标签: reactjs


【解决方案1】:

您可能正在寻找contextType 属性。它的工作原理如下:

1) 为其分配一个上下文对象;
2) 访问this.context 上提供的值。

import ThemeContext from '../context/ThemeContext'

class Header extends React.Component {
  // as a public class field
  static contextType = ThemeContext

  render() {
    const { toggleDark, dark } = this.context

    return (
      <HeaderWrapper>
        <span
          role="presentation"
          className="dark-switcher"
          onClick={toggleDark}
        >
          {dark ? <span>☀</span> : <span>☾</span>}
        </span>
      </HeaderWrapper>
    )
  }
}

// or as a property
Header.contextType = ThemeContext

我注意到您使用的 React 版本包含对钩子的支持 - 如果您愿意,useContext 钩子提供了一种利用上下文值的替代方法。

【讨论】:

  • 是的。这就是我试图实现的。感谢鲍威尔的帮助。 :D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-10
  • 2019-06-14
  • 1970-01-01
  • 1970-01-01
  • 2018-06-05
相关资源
最近更新 更多