最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Programatically addremove class generated by material ui - Stack Overflow

programmeradmin1浏览0评论

How can I programmatically add/ remove the material-UI classes that I defined in makeStyles() Here's my code:

import React from 'react';
import { DropboxIcon, GoogleDriveIcon, BoxIcon } from '../ponents/icons';
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles(theme => ({
    input: {
        display: 'none'
    },
    label: {
        display: 'inline-flex',
        marginRight: theme.spacing(2),
        marginLeft: theme.spacing(2),
        justifyCOntent: 'space-between',
        padding: theme.spacing(1, 1.5)
    },
    iconName: {
        marginLeft: theme.spacing(1)
    },
    iconsFormWrapper: {
        marginTop: theme.spacing(2)
    },
    selectedService: {
        backgroundColor: theme.palette.primary.dark,
        borderRadius: theme.spacing(1),
        color: '#ffffff',
        '& svg, img': {
            fill: '#ffffff!important',
            filter: 'brightness(0) invert(1)'
        }
    }

}));

const selectServiceHandle = (e) => {
    const optionName = document.getElementsByName("signup-service");
    optionName.classList.remove("selectedService")
    document.querySelectorAll(`input[value=${e.target.value}]`).classList.add("selectedService")
}

const SignupRadioIcons = () => {
    const classes = useStyles();
        return (
            <div className={classes.iconsFormWrapper}>
                <form>
                    <label className={`${classes.label} ${classes.selectedService}`}>
                         <DropboxIcon/> <span className={classes.iconName}>Dropbox</span>
                          <input type="radio" onChange={(e)=>selectServiceHandle(e)} name="signup-service" value="dropbox" className={classes.input} /> 
                    </label>
                    <label className={classes.label}>
                         <GoogleDriveIcon/> <span className={classes.iconName}>Google Drive</span>
                          <input type="radio" onChange={(e)=>selectServiceHandle(e)} name="signup-service" value="drive" className={classes.input} /> 
                    </label>
                    <label className={classes.label}>
                         <BoxIcon/> <span className={classes.iconName}>Box</span>
                          <input type="radio" onChange={(e)=>selectServiceHandle(e)} name="signup-service" value="box" className={classes.input} /> 
                    </label>
                </form>
            </div>
        )
}


export default SignupRadioIcons;

In my code, I defined a class called selectedService in my makeStyles() But I want to add/remove this class on every change event, Whenever a user click any input I want to remove this class from all other inputs and add it to the one where the user clicked. But this code is not working because the actual classes that is generated by material UI look like makeStyles-selectedService-224 and the postfix number keeps on changing on every refresh.

How can I programmatically add/ remove the material-UI classes that I defined in makeStyles() Here's my code:

import React from 'react';
import { DropboxIcon, GoogleDriveIcon, BoxIcon } from '../ponents/icons';
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles(theme => ({
    input: {
        display: 'none'
    },
    label: {
        display: 'inline-flex',
        marginRight: theme.spacing(2),
        marginLeft: theme.spacing(2),
        justifyCOntent: 'space-between',
        padding: theme.spacing(1, 1.5)
    },
    iconName: {
        marginLeft: theme.spacing(1)
    },
    iconsFormWrapper: {
        marginTop: theme.spacing(2)
    },
    selectedService: {
        backgroundColor: theme.palette.primary.dark,
        borderRadius: theme.spacing(1),
        color: '#ffffff',
        '& svg, img': {
            fill: '#ffffff!important',
            filter: 'brightness(0) invert(1)'
        }
    }

}));

const selectServiceHandle = (e) => {
    const optionName = document.getElementsByName("signup-service");
    optionName.classList.remove("selectedService")
    document.querySelectorAll(`input[value=${e.target.value}]`).classList.add("selectedService")
}

const SignupRadioIcons = () => {
    const classes = useStyles();
        return (
            <div className={classes.iconsFormWrapper}>
                <form>
                    <label className={`${classes.label} ${classes.selectedService}`}>
                         <DropboxIcon/> <span className={classes.iconName}>Dropbox</span>
                          <input type="radio" onChange={(e)=>selectServiceHandle(e)} name="signup-service" value="dropbox" className={classes.input} /> 
                    </label>
                    <label className={classes.label}>
                         <GoogleDriveIcon/> <span className={classes.iconName}>Google Drive</span>
                          <input type="radio" onChange={(e)=>selectServiceHandle(e)} name="signup-service" value="drive" className={classes.input} /> 
                    </label>
                    <label className={classes.label}>
                         <BoxIcon/> <span className={classes.iconName}>Box</span>
                          <input type="radio" onChange={(e)=>selectServiceHandle(e)} name="signup-service" value="box" className={classes.input} /> 
                    </label>
                </form>
            </div>
        )
}


export default SignupRadioIcons;

In my code, I defined a class called selectedService in my makeStyles() But I want to add/remove this class on every change event, Whenever a user click any input I want to remove this class from all other inputs and add it to the one where the user clicked. But this code is not working because the actual classes that is generated by material UI look like makeStyles-selectedService-224 and the postfix number keeps on changing on every refresh.

Share Improve this question edited Aug 11, 2019 at 20:24 Noob 2,8174 gold badges23 silver badges43 bronze badges asked Aug 11, 2019 at 20:15 WaeezWaeez 3394 gold badges13 silver badges29 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 3

You can set state to the currently selected radio's value, then use a conditional statement to check if the selected value equals the currently selected state in order to apply css.

I would remend converting your radio's into JSON objects, then looping through them - this makes things a lot easier.

I have provided an example of how to handle this without using a loop, as well as with using a loop in the SandBox below.

Example Code Using JSON & Looping:

import React, { useState } from "react";
import { makeStyles } from "@material-ui/core/styles";
import Dropbox from "./Dropbox.js";
import Box from "./Box.js";
import Drive from "./Drive.js";

const base = {
  fontSize: "20px"
};

const useStyles = makeStyles(theme => ({
  base: {
    ...base
  },
  selected: {
    ...base,
    fontSize: "40px",
    backgroundColor: "yellow",
    textDecorationLine: "underline"
  }
}));

const radioObjects = [
  {
    label: Dropbox,
    value: "dropbox"
  },
  {
    label: Drive,
    value: "drive"
  },
  {
    label: Box,
    value: "box"
  }
];

export default function WithLoop() {
  const classes = useStyles();
  const [currentlyChecked, setCurrentlyChecked] = useState();

  function handleChange(event) {
    setCurrentlyChecked(event.target.value);
    // do work
  }

  return (
    <div>
      <form>
        {radioObjects.map(RadioItem => {
          return (
            <div key={RadioItem.value}>
              <label
                className={
                  currentlyChecked === RadioItem.value
                    ? classes.selected
                    : classes.base
                }
              >
                <RadioItem.label />
                <input
                  value={RadioItem.value}
                  onChange={handleChange}
                  type="radio"
                  name="signup-service"
                />
              </label>
            </div>
          );
        })}
      </form>
    </div>
  );
}

Given you are using React, I'd suggest you use local state to determine when to apply the class

import React, { useState } from 'react';
const storageProviders = {
  Dropbox: 1,
  GoogleDrive: 2,
  Box: 3
};
...
const SignupRadioIcons = () => {
  const classes = useStyles();
  const [focusedInput, setFocusedInput] = useState(storageProviders.Dropbox);
  return (
    <div className={classes.iconsFormWrapper}>
      <form>
        <label className={`${classes.label} ${focusedInput === storageProviders.Dropbox ? classes.selectedService : ''}`}>
          <DropboxIcon/> <span className={classes.iconName}>Dropbox</span>
            <input type="radio" onChange={() => setFocusedInput(storageProviders.Dropbox)} name="signup-service" value="dropbox" className={classes.input} /> 
        </label>
        <label className={`${classes.label} ${focusedInput === storageProviders.GoogleDrive ? classes.selectedService : ''}`}>
          <GoogleDriveIcon/> <span className={classes.iconName}>Google Drive</span>
          <input type="radio" onChange={() => setFocusedInput(storageProviders.GoogleDrive)} name="signup-service" value="drive" className={classes.input} /> 
        </label>
        <label className={`${classes.label} ${focusedInput === storageProviders.Box ? classes.selectedService : ''}`}>
          <BoxIcon/> <span className={classes.iconName}>Box</span>
          <input type="radio" onChange={() => setFocusedInput(storageProviders.Box)} name="signup-service" value="box" className={classes.input} /> 
        </label>
      </form>
    </div>
  )
}

There's a mon pattern there that you could probably move into a reusable ponent but you get the jist of it.

This code will work if react version is more than 16

import React, { useState } from 'react';

const SignupRadioIcons = () => {
    const classes = useStyles();
    const [selectedService, setSelectedService]= useState('dropbox');

        return (
            <div className={classes.iconsFormWrapper}>
                <form>
                    <label className={`${classes.label} ${selectedService === 'dropbox' ? classes.selectedService : undefined}`}>
                         <DropboxIcon/> <span className={classes.iconName}>Dropbox</span>
                          <input type="radio" onChange={(e)=> setSelectedService('dropbox')} name="signup-service" value="dropbox" className={classes.input} /> 
                    </label>
                    <label  className={`${classes.label} ${selectedService === 'googleDrive' ? classes.selectedService : undefined}`}>
                         <GoogleDriveIcon/> <span className={classes.iconName}>Google Drive</span>
                          <input type="radio" onChange={(e)=> setSelectedService('googleDrive')} name="signup-service" value="drive" className={classes.input} /> 
                    </label>
                    <label className={`${classes.label} ${selectedService === 'box' ? classes.selectedService : undefined}`}>
                         <BoxIcon/> <span className={classes.iconName}>Box</span>
                          <input type="radio" onChange={(e)=> setSelectedService('box')} name="signup-service" value="box" className={classes.input} /> 
                    </label>
                </form>
            </div>
        )
}

You can use ClassNameGenerator

To rename ponent class name:

import { unstable_ClassNameGenerator as ClassNameGenerator } from '@mui/material/className';

ClassNameGenerator.configure((ponentName) => ponentName.replace('Mui', ''));

For example:

ClassNameGenerator.configure((MuiSelect) => MuiSelect.replace('Mui', ''));

Where "the" Mui is the prefix of your ponent (all the Material ponents use the same prefix).

Have a look at the documentation

发布评论

评论列表(0)

  1. 暂无评论