Come applicare lo stile ai componenti utilizzando makeStyles e avere ancora metodi del ciclo di vita nell'interfaccia utente dei materiali?


117

Ottengo l'errore seguente ogni volta che provo a utilizzare makeStyles()un componente con metodi del ciclo di vita:

Chiamata hook non valida. Gli hook possono essere chiamati solo all'interno del corpo di un componente funzione. Ciò potrebbe accadere per uno dei seguenti motivi:

  1. Potresti avere versioni non corrispondenti di React e del renderer (come React DOM)
  2. Potresti infrangere le regole degli Hooks
  3. Potresti avere più di una copia di React nella stessa app

Di seguito è riportato un piccolo esempio di codice che produce questo errore. Altri esempi assegnano classi anche a elementi figlio. Non riesco a trovare nulla nella documentazione di MUI che mostri altri modi di utilizzare makeStylese abbia la possibilità di utilizzare i metodi del ciclo di vita.

    import React, { Component } from 'react';
    import { Redirect } from 'react-router-dom';

    import { Container, makeStyles } from '@material-ui/core';

    import LogoButtonCard from '../molecules/Cards/LogoButtonCard';

    const useStyles = makeStyles(theme => ({
      root: {
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
      },
    }));

    const classes = useStyles();

    class Welcome extends Component {
      render() {
        if (this.props.auth.isAuthenticated()) {
          return <Redirect to="/" />;
        }
        return (
          <Container maxWidth={false} className={classes.root}>
            <LogoButtonCard
              buttonText="Enter"
              headerText="Welcome to PlatformX"
              buttonAction={this.props.auth.login}
            />
          </Container>
        );
      }
    }

    export default Welcome;

Risposte:


170

Ciao invece di usare l'API hook, dovresti usare l'API del componente di ordine superiore come menzionato qui

Modificherò l'esempio nella documentazione per soddisfare le tue esigenze per il componente di classe

import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/styles';
import Button from '@material-ui/core/Button';

const styles = theme => ({
  root: {
    background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
    border: 0,
    borderRadius: 3,
    boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
    color: 'white',
    height: 48,
    padding: '0 30px',
  },
});

class HigherOrderComponent extends React.Component {

  render(){
    const { classes } = this.props;
    return (
      <Button className={classes.root}>Higher-order component</Button>
      );
  }
}

HigherOrderComponent.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(HigherOrderComponent);

4
Ho invalid hook callgirato in tondo con questo bug e l' errore - Grazie per avermi portato nella giusta direzione !!
Kitson

1
@ Jax-p vedi la mia soluzione
Matt Weber

4
@VikasKumar Con questo approccio, come posso utilizzare il tema dell'app nei miei stili? Fe submit: {margin: appTheme.spacing (3, 0, 2),},
Sergey Aldoukhov

1
Grazie. Ma un problema! Non l'hai usato themenel tuo stylescorpo (@SergeyAldoukhov lo ha già detto). Quando lo uso, ottengo questo errore: "Impossibile leggere la proprietà 'X' di undefined" ed undefinedè themeesattamente! Ho provato withStyles(styles(myDefinedMuiTheme))(...)e ha funzionato correttamente.
Mir-Ismaili

1
@Kitson, probabilmente hai usato makeStyles() ( styles = makeStyles(theme => ({...})) . Inoltre, se vuoi uno stile dipendente dal tema, vedi il mio commento precedente.
Mir-Ismaili

41

Ho usato withStylesinvece dimakeStyle

EX:

import { withStyles } from '@material-ui/core/styles';
import React, {Component} from "react";

const useStyles = theme => ({
        root: {
           flexGrow: 1,
         },
  });

class App extends Component {
       render() {
                const { classes } = this.props;
                return(
                    <div className={classes.root}>
                       Test
                </div>
                )
          }
} 

export default withStyles(useStyles)(App)

18

Quello che abbiamo finito per fare è stato smettere di usare i componenti di classe e creare componenti funzionali, usandouseEffect() l' API Hooks per i metodi del ciclo di vita . Ciò consente di continuare a utilizzarli makeStyles()con i metodi del ciclo di vita senza aggiungere la complicazione della creazione di componenti di ordine superiore . Che è molto più semplice.

Esempio:

import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { Redirect } from 'react-router-dom';

import { Container, makeStyles } from '@material-ui/core';

import LogoButtonCard from '../molecules/Cards/LogoButtonCard';

const useStyles = makeStyles(theme => ({
  root: {
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    margin: theme.spacing(1)
  },
  highlight: {
    backgroundColor: 'red',
  }
}));

// Highlight is a bool
const Welcome = ({highlight}) => { 
  const [userName, setUserName] = useState('');
  const [isAuthenticated, setIsAuthenticated] = useState(true);
  const classes = useStyles();

  useEffect(() => {
    axios.get('example.com/api/username/12')
         .then(res => setUserName(res.userName));
  }, []);

  if (!isAuthenticated()) {
    return <Redirect to="/" />;
  }
  return (
    <Container maxWidth={false} className={highlight ? classes.highlight : classes.root}>
      <LogoButtonCard
        buttonText="Enter"
        headerText={isAuthenticated && `Welcome, ${userName}`}
        buttonAction={login}
      />
   </Container>
   );
  }
}

export default Welcome;

2
Per le persone che utilizzano l'aggiornamento di React 16.8 Hooks o superiore, penso che passare a una funzione sia una soluzione ideale. In 16.8 le funzioni possono accedere agli hook di stato e del ciclo di vita.
Tim

5
Sono sconcertato perché questo ha ottenuto voti negativi. React ha reso abbastanza chiaro che le classi vengono sostituite da componenti funzionali con Hooks. reactjs.org/docs/…
Matt Weber

3
Non ho votato in negativo, ma è un problema impostare lo stato iniziale in modo pigro usando xhr mentre si utilizza il componente basato sulla funzione. Con il componente di classe posso impostare lo stato iniziale su quello che voglio, quindi utilizzare ajax quindi setState una volta che arriva la risposta. Non ho assolutamente idea di come farlo bene con una funzione.
mlt

1
Useresti useEffect. Nel caso precedente, stai impostando lo stato iniziale di userName su una stringa vuota, quindi dopo una chiamata API assicurati di useEffectutilizzarla setUserName(response). Aggiungerò un esempio sopra e un collegamento a un articolo con maggiori informazioni sull'uso di useEffect per i metodi del ciclo di vita. dev.to/prototyp/…
Matt Weber

3
Questo è stato votato perché la programmazione funzionale fa schifo nelle applicazioni reali che necessitano di architettura. Migliora la già proliferata tendenza dei programmatori js a fare grandi cazzate di codice spaghetti che sono davvero, davvero difficili da leggere / seguire e impossibili da suddividere in componenti ragionevoli. Se reagire sta spingendo in questo modo, stanno commettendo un grosso errore e non li seguirò lì.
RickyA

2

useStyles è un hook React pensato per essere utilizzato in componenti funzionali e non può essere utilizzato in componenti di classe.

Da React:

Gli hook ti consentono di utilizzare lo stato e altre funzionalità di React senza scrivere una classe.

Inoltre dovresti chiamare useStyleshook all'interno della tua funzione come;

function Welcome() {
  const classes = useStyles();
...

Se vuoi usare gli hook, ecco il tuo breve componente di classe cambiato in componente funzionale;

import React from "react";
import { Container, makeStyles } from "@material-ui/core";

const useStyles = makeStyles({
  root: {
    background: "linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)",
    border: 0,
    borderRadius: 3,
    boxShadow: "0 3px 5px 2px rgba(255, 105, 135, .3)",
    color: "white",
    height: 48,
    padding: "0 30px"
  }
});

function Welcome() {
  const classes = useStyles();
  return (
    <Container className={classes.root}>
      <h1>Welcome</h1>
    </Container>
  );
}

export default Welcome;

🏓 su ↓ CodeSandBox ↓

Modifica gli hook di React


0

Un'altra soluzione può essere utilizzata per i componenti di classe: basta sovrascrivere le proprietà del tema MUI predefinite con MuiThemeProvider. Ciò offrirà maggiore flessibilità rispetto ad altri metodi: puoi utilizzare più di un MuiThemeProvider all'interno del componente principale.

semplici passaggi:

  1. importa MuiThemeProvider nel componente di classe
  2. importa createMuiTheme nel componente di classe
  3. crea un nuovo tema
  4. avvolgere il componente MUI di destinazione che si desidera applicare allo stile con MuiThemeProvider e il tema personalizzato

per favore, controlla questo documento per maggiori dettagli: https://material-ui.com/customization/theming/

import React from 'react';
import PropTypes from 'prop-types';
import Button from '@material-ui/core/Button';

import { MuiThemeProvider } from '@material-ui/core/styles';
import { createMuiTheme } from '@material-ui/core/styles';

const InputTheme = createMuiTheme({
    overrides: {
        root: {
            background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
            border: 0,
            borderRadius: 3,
            boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
            color: 'white',
            height: 48,
            padding: '0 30px',
        },
    }
});

class HigherOrderComponent extends React.Component {

    render(){
        const { classes } = this.props;
        return (
            <MuiThemeProvider theme={InputTheme}>
                <Button className={classes.root}>Higher-order component</Button>
            </MuiThemeProvider>
        );
    }
}

HigherOrderComponent.propTypes = {
    classes: PropTypes.object.isRequired,
};

export default HigherOrderComponent;


-1

Invece di convertire la classe in una funzione, un semplice passaggio sarebbe creare una funzione per includere jsx per il componente che utilizza le 'classi', nel tuo caso il <container></container>e quindi chiamare questa funzione all'interno del ritorno della classe render () come tag. In questo modo stai spostando l'hook a una funzione dalla classe. Ha funzionato perfettamente per me. Nel mio caso è stata una funzione <table>che ho spostato su una funzione: TableStmt all'esterno e ho chiamato questa funzione all'interno del rendering come<TableStmt/>

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.