Включить глобальную тематику с эмоциями?

Я подписался на https://github.com/emotion-js/emotion/issues/546, в котором автор Emotion Кай упоминает решение, хотя я не совсем понимаю его.

Поэтому я сделал небольшой CodeSandBox, в котором реализованы детали, указанные в проблеме. Как я могу заставить тему background-color работать в injectGlobal?


person deadcoder0904    schedule 01.08.2018    source источник


Ответы (2)


Обновление для тех, кто использует эмоции 10:

import React from 'react'
import { useTheme, ThemeProvider } from 'emotion-theming'
import { css, Global } from '@emotion/core'

const GlobalStyles = () => {
  const theme = useTheme()
  return (
    <Global styles={css`
      body {
        background: ${theme.bg};
      }
    `} />
  )
}


const App = () => (
  <ThemeProvider theme={{ bg: 'tomato' }}>
    <main>
      <h1>Hi</h1>
      <GlobalStyles />
    </main>
  </ThemeProvider>
)

person Derek Nguyen    schedule 02.07.2019

Я нашел решение. Полное решение можно найти по адресу https://codesandbox.io/s/r76p996zym или https://github.com/deadcoder0904/emotion-global-theming

Создайте theme.js файл, содержащий темы вашего приложения

theme.js

export const theme = {
  LIGHT: {
    textColor: "black",
    bgColor: "white"
  },
  DARK: {
    textColor: "white",
    bgColor: "black"
  }
};

Оберните Global Компонент в withTheme, и он должен иметь theme опору

Global.js

import React from "react";
import { injectGlobal } from "react-emotion";
import { withTheme } from "emotion-theming";

class Global extends React.Component {
  componentDidUpdate(prevProps) {
    if (this.props.theme.bgColor !== prevProps.theme.bgColor) {
      window.document.body.style.backgroundColor = this.props.theme.bgColor;
    }
    if (this.props.theme.textColor !== prevProps.theme.textColor) {
      window.document.body.style.color = this.props.theme.textColor;
    }
  }

  render() {
    injectGlobal`
      color: ${this.props.theme.textColor};
      background-color: ${this.props.theme.bgColor};
    `;
    return React.Children.only(this.props.children);
  }
}

export default withTheme(Global);

А затем оберните компонент App компонентом Global. Поскольку компонент Global требует theme, он должен быть заключен в ThemeProvider

index.js

import React from "react";
import ReactDOM from "react-dom";
import { ThemeProvider } from "emotion-theming";

import Global from "./injectGlobal";
import { theme } from "./theme";

class App extends React.Component {
  state = {
    isLight: true,
    title: "Light Theme",
    theme: theme.LIGHT
  };

  _toggleTheme = () => {
    const { isLight } = this.state;
    const title = isLight ? "Dark Theme" : "Light Theme";
    const newTheme = isLight ? theme.DARK : theme.LIGHT;
    this.setState({
      isLight: !isLight,
      title,
      theme: newTheme
    });
  };

  render() {
    const { title, theme } = this.state;
    return (
      <ThemeProvider theme={theme}>
        <Global>
          <React.Fragment>
            <h1>{title}</h1>
            <button onClick={this._toggleTheme}>Toggle Theme</button>
          </React.Fragment>
        </Global>
      </ThemeProvider>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Примечание. Этот ответ действителен только до выпусков Emotion 10 и изменений API. Если версия Emotion меньше 10, воспользуйтесь этим решением.

person deadcoder0904    schedule 01.08.2018