goober icon indicating copy to clipboard operation
goober copied to clipboard

Using createGlobalStyles together with themes leads to incorrect behaviour

Open marvson opened this issue 2 years ago • 0 comments

When using a theme, if a button is used to change the background color for the body tag, for example, the first time it works fine, but the second time, it doesn't. Digging a little, I noticed that every time I click the button, changing the theme values, a new style tag is added to head. The first time it overwrites the default value, but once you want to go back to the default value, it was already overwritten and there is no change. I guess that the fix is updating the global style tag that was added by createGlobalStyles rather than adding a new style tag.

Minimal reproduction, replacing the code from the CodeSandbox for preact from here.

import "./style";
import { Component, render, h, createContext } from "preact";
import { useContext, useState } from "preact/hooks";
import { Result } from "./result";
import { styled, setup } from "goober";
import { createGlobalStyles } from "goober/global";

const Theme = createContext();
const useTheme = () => useContext(Theme);
setup(h, undefined, useTheme);

const SEARCH = "//api.github.com/search/repositories";

const Title = styled("h1")`
  text-align: center;
`;

const StyledResult = styled("div")`
  padding: 10px;
  margin: 10px;
  background: white;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.5);
`;

const GlobalStyle = createGlobalStyles`
  html, body {
    background-color: ${({ theme }) => theme.a};
  }
`;

export default class App extends Component {
  constructor () {
    super();
    this.state = {a: '#ffff00'}
  }

  componentDidMount() {
    fetch(`${SEARCH}?q=preact`)
      .then((r) => r.json())
      .then((json) => {
        this.setState({
          results: (json && json.items) || []
        });
      });
  }

  render(props, { results = [] }) {
    return (
      <Theme.Provider value={{ a: this.state.a }}>
        <div>
          <GlobalStyle />
          <Title>Example</Title>
          <div class="list">
            {results.map((result) => (
              <StyledResult>
                <Result result={result} />
              </StyledResult>
            ))}
          </div>
          <button onClick={() => {
            if (this.state.a === '#ffff00') {
              this.setState({a: '#00ffff'});
            } else {
              this.setState({a: '#ffff00'});
            }
          }}>Change</button>
        </div>
      </Theme.Provider>
    );
  }
}

if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

marvson avatar Sep 28 '21 17:09 marvson