【问题标题】:Custom React Component styles being overwritten by Material-UI style自定义 React 组件样式被 Material-UI 样式覆盖
【发布时间】:2020-05-23 22:37:25
【问题描述】:

相关问题:Styles being overwritten by Material-UI style

我正在 Material UI 之上创建一个组件库。使用 JSS,我希望能够将样式传递给我的自定义组件。但是,我遇到了 Material-ui 的根样式比我传入的具有更高特异性的问题。我尝试使用 classes 语法覆盖 material-ui 组件的默认样式,但它只是创建了另一个具有类似的类名称和更高的特异性 (makeStyles-root-51)。

使用自定义组件:

import React from 'react';
import {gSelect} from 'g-react-component-library/dist'
import {createUseStyles} from 'react-jss'

const useStyles = createUseStyles({
    gSelect: {margin: "15px"},
    example: {float: "left", display: "inline-block", whiteSpace: 'nowrap', verticalAlign: 'top'}
});

function App() {

    const classes = useStyles();
    return (
        <div className={classes.example}>
            <div className={classes.separator}>
                <div>Selects:</div>
                <gSelect default={1} classes={{gSelect: classes.gSelect}} callback={(e)=>{console.log(`${e} selected`)}} options={[1,2,3,4]}/>
                <gSelect default={'One'} classes={{gSelect: classes.gSelect}} callback={(e)=>{console.log(`${e} selected`)}} options={["One", "Two", "Three", "Four"]}/>
            </div>
        </div>
    );
}

export default App;

实际的自定义组件:

import React, {useState} from 'react';
import {Button, Select, FormControl, MenuItem, InputLabel} from '@material-ui/core'
import {makeStyles} from '@material-ui/styles'
import PropTypes from 'prop-types'

const gSelect = (props) => {

    const [value, setValue] = useState();

    const handleChange = event => {
        props.callback(event.target.value);
        setValue(event.target.value);
    };

    const useStyles = makeStyles({
        select: {
            border: 'solid #33333366 1px',
            color: 'rgba(51, 51, 51, 0.66)',
            fontWeight: '700',
            backgroundColor: 'white',
            outline: 'none',
            borderRadius: '5px',
            textAlign: 'left',
            width: '300px',
            position: 'relative',
        },
        root: {

        }
    });

    const classes = useStyles(props);
    return (
        <FormControl classes={{root: classes.gSelect}}>
        <InputLabel id="demo-simple-select-label">{props.default}</InputLabel>
        <Select value={value} onChange={handleChange} className={classes.select}>
            {props.options.map((option, index) => {
                return <MenuItem key={`${option}_${index}`} value={option}>{option}</MenuItem>
            })}
        </Select>
        </FormControl>
    )
};

gSelect.propTypes = {
    callback: PropTypes.func.isRequired,
    options: PropTypes.array.isRequired,
    default: PropTypes.oneOfType([
        PropTypes.string,
        PropTypes.number
    ]).isRequired,
    disabled: PropTypes.bool,
    width: PropTypes.string
};

module.exports = {
    gSelect
};

【问题讨论】:

  • 你不应该在组件内部创建 useStyles 钩子,这违背了目的。
  • 怎么样?如果我想在 Material-UI 之上创建一个自定义组件库,你必须以某种方式为其提供自定义样式。
  • 我已经在下面的回答中解释了 - 问题的关键在于 classes 应该通过道具传递,并且您应该将这些道具传递给您的钩子 - 材质 UI 完成了连接传递的所有魔力在你自己的课堂上。我个人更喜欢 withStyles hoc,因为所有这些逻辑都是自动为您处理的,您不必担心忘记将道具传递给 useStyles 钩子。
  • @Adam,我已经按照您的建议进行了更改。但是,我仍然遇到 MUI 的根类具有更高的特异性并覆盖我的边距的问题。另外,我已经从这个问题的源代码中删减了很多代码,所以如果有一些明显的问题可能就是你所看到的。在我最初的问题中,我意识到我传递给组件的样式与它在内部用于自定义选择的样式相同。这只是我为问题编辑内容的错误。我应该在更新的问题中修复它。
  • 如果你可以发布一个 codepen/stackblitz 来展示一个问题(不一定是这个确切的代码,只是类似的东西)它会走很长的路。

标签: javascript reactjs material-ui react-component jss


【解决方案1】:

你做错了。 GSelect 应该接收这样的类:

应用内:

<GSelect default={1} classes={{gSelect:classes.gSelect}} callback={(e)=>{console.log(`${e} selected`)}} options={[1,2,3,4]}/>

然后在GSelect:

const useStyles = createStyles(...your styles); // call this hook factory outside your render

const GSelect = props => {
   const classes = useStyles(props) <- props contains an object called classes with a property gselect that gets merged into yours

   <Select value={value} onChange={handleChange} classes={{root:classes.gSelect}}>
}

编辑:至于我关于在组件之外创建钩子的原始评论,我的意思是这样做:


// move this outside of your render
    const useStyles = createUseStyles({
        gSelect: {margin: "15px"},
        separator: {marginTop: "15px"},
        example: {float: "left", display: "inline-block", whiteSpace: 'nowrap', verticalAlign: 'top'}
    });

function App() {
    // use it inside of your render
    const classes = useStyles();
    ...
}

通读本节及以下两节,过一会会点击:https://material-ui.com/styles/advanced/#overriding-styles-classes-prop

【讨论】:

    【解决方案2】:

    最终将样式传递给自定义组件的解决方案非常简单。虽然@Adam 以措辞方式回答了我的问题,但我最终得到的解决方案如下:

    使用自定义组件:

    import React from 'react';
    import {gSelect} from 'g-react-component-library/dist'
    import { makeStyles } from "@material-ui/core/styles";
    
    const useStyles = makeStyles ({
        gSelect: {margin: "15px"},
        example: {float: "left", display: "inline-block", whiteSpace: 'nowrap', verticalAlign: 'top'}
    });
    
    function App() {
    
        const classes = useStyles();
        return (
            <div className={classes.example}>
                <div className={classes.separator}>
                    <div>Selects:</div>
                    <gSelect default={1} className={classes.gSelect} callback={(e)=>{console.log(`${e} selected`)}} options={[1,2,3,4]}/>
                    <gSelect default={'One'} className={classes.gSelect} callback={(e)=>{console.log(`${e} selected`)}} options={["One", "Two", "Three", "Four"]}/>
                </div>
            </div>
        );
    }
    
    export default App;
    

    上面的修复包括:

    • createUseStyles@material-ui/core/styles 切换到makeStyles
    • 使用className={classes.gSelect} 而不是classes={{root: ...}}

    实际的自定义组件:

    import React, {useState} from 'react';
    import {Button, Select, FormControl, MenuItem, InputLabel} from '@material-ui/core'
    import {makeStyles} from '@material-ui/styles'
    import PropTypes from 'prop-types'
    
    const gSelect = (props) => {
    
    const [value, setValue] = useState();
    
    const handleChange = event => {
        props.callback(event.target.value);
        setValue(event.target.value);
    };
    
    const useStyles = makeStyles({
        select: {
            border: 'solid #33333366 1px',
            color: 'rgba(51, 51, 51, 0.66)',
            fontWeight: '700',
            backgroundColor: 'white',
            outline: 'none',
            borderRadius: '5px',
            textAlign: 'left',
            width: '300px',
            position: 'relative',
        }
    });
    
    const classes = useStyles();
    return (
        <FormControl className={props.className}>
        <InputLabel id="demo-simple-select-label">{props.default}</InputLabel>
        <Select value={value} onChange={handleChange} className={classes.select}>
            {props.options.map((option, index) => {
                return <MenuItem key={`${option}_${index}`} value={option}>{option}</MenuItem>
            })}
        </Select>
        </FormControl>
    )
    };
    
    gSelect.propTypes = {
        callback: PropTypes.func.isRequired,
        options: PropTypes.array.isRequired,
        default: PropTypes.oneOfType([
            PropTypes.string,
            PropTypes.number
        ]).isRequired,
        disabled: PropTypes.bool,
        width: PropTypes.string
    };
    
    module.exports = {
        gSelect
    };
    

    上面的修复包括:

    • &lt;FormControl&gt; 上使用className={props.className}

    【讨论】:

      猜你喜欢
      • 2020-05-27
      • 1970-01-01
      • 2020-01-30
      • 2019-03-07
      • 2017-04-02
      • 1970-01-01
      • 2020-07-16
      • 2021-02-19
      • 2020-08-10
      相关资源
      最近更新 更多