question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Discussion: are callbacks to withStyles always the best way to obtain the theme?

See original GitHub issue

This question occurred to me while thinking about #9192, and I’ll repost part of my comment there:

If one is not developing reusable MUI components, but instead making an app, is there any advantage to using withStyles with a callback, vs. exporting your theme from a module and then importing it everywhere that you want to use it? For example,

// src/theme.ts

import createMuiTheme from 'material-ui/styles/createMuiTheme';
import { red, purple } from 'material-ui/colors';

export default createMuiTheme({
  palette: {
    primary: red,
    secondary: purple,
  },
});
// src/index.tsx

import * as React from 'react';
import App from './App';
import theme from './theme';

ReactDOM.render(
  <MuiThemeProvider theme={theme}>
    <App />
  </MuiThemeProvider>,
  document.getElementById('root')
);
// src/component.ts

import * as React from 'react';
import { withStyles } from 'material-ui/styles';
import theme from './theme';

export default withStyles({
  root: {
    margin: theme.spacing.unit * 3,
  },
})(...);

This is particularly relevant to TypeScript for 2 reasons:

  • it seems impossible to solve #9192 in a well-typed way with the callback approach
  • callbacks interfere with type inference because of this TypeScript issue. If you look through the material-ui issue tracker you’ll find that this has been the source of all kinds of confusion. The workaround, which is not obvious at all, requires annotating withStyles with a union of all your class keys, e.g. withStyles<'root'| | 'docked' | 'paper' | 'modal'>(/* ... */). Various complex solutions have been proposed for this, notably #8829 and #9105.

Simply exporting a global theme and then importing it where you need it rather than using callbacks everywhere magically makes all these problems melt away.

It seems like the advantage of using a callback is that it makes your components more modular; you can ship them as a library and others can use them within any MuiThemeProvider. But in many cases people aren’t making reusable libraries, they’re making an app, in which case it seems like it’s fine to just reference a global theme.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:5
  • Comments:25 (25 by maintainers)

github_iconTop GitHub Comments

4reactions
pelotomcommented, Dec 13, 2017

This gives a natural way to accomplish a feature many have been asking for: styles that depend on props. Just move the definition of styles inside the component.

class MyComponent extends React.Component<Props> {
  render() {
    return (
      <Styled styles={this.styles} options={options}>
        {classes =>
          <...>
        }
      </Styled>
    )
  }

  styles = {
    // ... can depend on `this.props`
  }
}
2reactions
Bnayacommented, Jan 9, 2018

I have another iteration It gives the class names by inferr, supports the them via context, expose type that you can use separately. (See the style: typeof Styled.style)

import { WithStyles } from "material-ui";
import { Theme } from "material-ui/styles";
import withStyles from "material-ui/styles/withStyles";
import * as React from "react";

interface IStyledProps<ClassKey extends string> {
  children(style: WithStyles<ClassKey>): JSX.Element;
}

type stylesParamType<ClassKey extends string> = (
  theme: Theme,
) => Record<ClassKey, React.CSSProperties> | Record<ClassKey, React.CSSProperties>;

export function createStyled<ClassKey extends string>(stylesParam: stylesParamType<ClassKey>) {
  const wrapperComponent = withStyles(stylesParam);

  const createdStyled: React.StatelessComponent<IStyledProps<ClassKey>> = function createdStyledComponent(props) {
    return React.createElement(
      wrapperComponent(stylePropsFromWithStyles => {
        return props.children(stylePropsFromWithStyles);
      }),
    );
  };

  Object.defineProperty(createdStyled, "style", {
    get() {
      throw new Error("style prop is here only for TypeScript inference. use typeof Styled.style for the type");
    },
  });

  // style is just for pulling the types
  return createdStyled as typeof createdStyled & { style: WithStyles<ClassKey> };
}

How to use:

const styles = (theme: Theme) => ({
  root: {
    width: "100%",
    background: theme.palette.background.paper,
    flex: "1",
    overflowY: "scroll",
  } as React.CSSProperties,
  preventInput: {
    pointerEvents: "none",
  },
});

const Styled = createStyled(styles);

function InnerComponent(props: { title: string; style: typeof Styled.style }) {
  return <div className={props.style.classes.root}>{props.title}</div>;
}

function OutterComponent(props: { title: string }) {
  return (
    <Styled>
      {s => {
        return <InnerComponent {...props} style={s}/>;
      }}
    </Styled>
  );
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Discussion: are callbacks to withStyles always the best way to obtain ...
Discussion : are callbacks to withStyles always the best way to obtain the theme? ... advantage to using withStyles with a callback, vs....
Read more >
material ui withStyles and WithTheme - How to access theme
withStyles function can accept a callback instead of an object giving you the access to the theme object like this
Read more >
Migrating from JSS (optional) - Material UI - MUI
This guide explains how to migrate from JSS to Emotion when updating from Material UI v4 to v5.
Read more >
Understanding the Event Loop, Callbacks, Promises, and ...
The task is to get the third function to always delay execution until after the ... Now that you have learned how to...
Read more >
transformers wikia
Transformer Prestashop Theme is an elegant, powerful, and fully-responsive ... fear of heights, but eventually learns how to become his 'perfect' partner.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found