Reputation: 599
I've been using Material UI components to create my own custom reusable components package. Here is an example of custom component located in package, just for demo purpose:
import PropTypes from 'prop-types';
import {makeStyles, ThemeProvider} from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
const useStyles = makeStyles({
'buttonPackage': {
backgroundColor: theme.palette.primary.main,
color: 'rgba(12, 0, 0, 1)',
minWidth: '147px',
padding: '8px 8px 9px 8px',
},
});
const CustomButton = ({children, theme}) => {
const classes = useStyles();
return (
<ThemeProvider theme={theme}>
<Button className={classes.buttonPackage}>
{children}
</Button>
</ThemeProvider>
);
};
export default CustomButton;
If it is not wrapped in ThemeProvider, global theme variables are not applied to custom component, although whole app is wrapped in ThemeProvider.
The problem occurs when I try to do further customization in React app part, for components that have very specific styling and cannot be considered as reusable. Here is an example of React view component, containing both custom component from package and component that is customized inside view component, again, this is just a demo code:
import React from 'react';
import {makeStyles} from '@material-ui/core/styles';
import {Button} from '@material-ui/core';
import {CustomButton, theme} from '@name-of-my-package/ui-components';
const useStyles = makeStyles(theme => ({
buttonApp: {
height: '100%',
},
}));
const GenericView = () => {
const classes = useStyles();
return (
<React.Fragment>
<CustomButton theme={theme}>Button imported from package</CustomButton>
<Button className={classes.buttonApp}/>Button customized in app</Button>
</React.Fragment>
);
};
export default GenericView;
When used in development, everything works fine. When used in production, some styling properties are shared between components customized in package and react app. Valid classes are bundled, but are not applied on first load of the page. When you click around the application (example, change route from navigation component), valid styles are applied and everything looks OK. I noticed that there is style overlapping between component customized in reusable component package, and component that is customized in React app.
Is this approach even possible, having custom component package and do further customization in app part, including Themes?
UPDATE 16.06.2020. : for now, solution is to completely not use JSS styling in app part of the project. JSS styling classes made in app part of the project overlap with names of JSS styling classes made in reusable components package and that causes the issue.
Upvotes: 2
Views: 4030
Reputation: 599
Solution for this problem included several steps:
alias: {
'react': require.resolve('react'),
'react-dom': require.resolve('react-dom'),
'@material-ui/core': path.resolve('./node_modules/@material-ui/core'),
'@material-ui/core/styles': path.resolve('./node_modules/@material-ui/core/styles'),
'@material-ui/lab': path.resolve('./node_modules/@material-ui/lab'),
'@material-ui/icons': path.resolve('./node_modules/@material-ui/icons'),
'@material-ui/pickers': path.resolve('./node_modules/@material-ui/pickers'),
},
import Button from '@material-ui/core/Button';
import it like this:
import {Button} from '@material-ui/core';
external: [
'react',
'react-dom',
'@material-ui/core',
'@material-ui/core/styles',
'@material-ui/lab',
'@material-ui/icons',
'@material-ui/pickers',
],
import React from 'react';
import {
StylesProvider,
createGenerateClassName,
} from '@material-ui/core/styles';
const generateClassName = createGenerateClassName({
productionPrefix: 'so', // change this string to whatever you like
seed: 'StackOverflow', // change this string to whatever you like
});
const MyStylesProvider = props => {
return (
<StylesProvider
injectFirst={true}
generateClassName={generateClassName}
>
{props.children}
</StylesProvider>
);
};
export default MyStylesProvider;
then I use it in React part of the app like this:
import React from 'react';
import {theme, MyStylesProvider} from '@package/reusable-components';
import {renderRoutes} from 'react-router-config';
import {ThemeProvider} from '@material-ui/core/styles';
import {CssBaseline} from '@material-ui/core';
const AppView = ({route}) => (
<ThemeProvider theme={theme}>
<CssBaseline />
<MyStylesProvider>
{renderRoutes(route.routes)}
</MyStylesProvider>
</ThemeProvider>
);
export default AppView;
This may not be the most optimal way to do it, but it works. I would love to hear other people's opinions and experiences with exporting reusable Material UI components.
Upvotes: 1