airbnb / react-with-styles

Use CSS-in-JavaScript with themes for React without being tightly coupled to one implementation

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Receive component props in decorator

Andreyco opened this issue · comments

Receive props passed to component in decorator function in order to create style definition.

Example:

function Avatar({ styles }) {
  return <Image style={styles.image} />
}

const AvatarWithStyle = withStyles(({ color }, ownProps) => ({
  image: {
    width: ownProps.imageSize,
    height: ownProps.imageSize,
    borderRadius: ownProps.imageSize / 2,
  },
}))(Avatar);

Will pay more attention later in order to discover whether it's possible with existing implementation.

While this would be convenient, I'm not sure this is a great idea for performance. If you are working with a style that has high-cardinality, it is probably a bad choice to put that through withStyles. And low-cardinality styles can be specified pretty easily in the standard way ({...css(isFoo && styles.foo)}). By keeping props out of this function, the API and usage is clear and consistent.

As I looked into the code, performance related issue come up. I must agree with you - cons of this approach surpass its pros.

commented

I am searching for a solution to set the backgroundImage using a url from props.

It's not possible to define all the possible images inside the withStyles hoc because file names are updated each build. Therefore I cannot use ({...css(imageFoo && styles.imageFoo, imageBaz && styles.imageBaz)})

Any suggestions?

Put the filenames in a JSON file, under hardcoded key names, recompute it every build, import the JSON file in the file?

commented

I didn't mention that the data set will grow over time so the solution should scale and work with variable image url's.

It'd take a pretty massive data set for that solution to not work. Regardless, hardcoding the image inside the component is way less scalable than my JSON suggestion - perhaps there's a better solution that doesn't involve dynamic filenames being used in code.

commented

Thanks for your help. I've looked at the possibilities and I have written a hoc which takes a function that adds specific props as a theme, this worked best for me.

Hi @bonjowi.
I am looking to do something similar to what you wanted to achieve. Could you paste a sample of how you were able to achieve this?

commented

Hi @Amandeepsinghghai

The HOC

import React from 'react';
import { ThemeProvider, ThemedStyleSheet } from '../styles/withStyles';

const withTheme = (themeName, propsMapper) => Component => {
    class WithTheme extends React.Component {
        constructor(props, context) {
            super(props, context);
            ThemedStyleSheet.registerTheme(themeName, propsMapper(props));
        }

        componentWillReceiveProps(nextProps) {
            ThemedStyleSheet.registerTheme(themeName, propsMapper(nextProps));
        }

        render() {
            return (
                <ThemeProvider name={themeName}>
                    <Component {...this.props} />
                </ThemeProvider>
            );
        }
    }

    return WithTheme;
};

export default withTheme;

The Component

import React from 'react';
import compose from 'recompose/compose';
import withTheme from '../withTheme';

const styles = ({ background, media }) => {
    return {
        root: {
            backgroundImage: background,
        },
    };
});

function Component({ styles }) {
    return <div {...css(styles.root)}/>;
}

export default compose(
    withTheme('yourThemeName', ({ data }) => ({
        background: data.background,
    })),
    withStyles(styles)
)(Component);