Wie kann man Komponenten mit makeStyles formatieren und trotzdem Lebenszyklusmethoden in der Material-Benutzeroberfläche verwenden?


102

Ich erhalte die folgende Fehlermeldung, wenn ich versuche, sie makeStyles()mit einer Komponente mit Lebenszyklusmethoden zu verwenden:

Ungültiger Hook-Aufruf. Hooks können nur innerhalb des Körpers einer Funktionskomponente aufgerufen werden. Dies kann aus einem der folgenden Gründe geschehen:

  1. Möglicherweise stimmen Versionen von React und des Renderers nicht überein (z. B. React DOM).
  2. Möglicherweise verstoßen Sie gegen die Hook-Regeln
  3. Möglicherweise haben Sie mehr als eine Kopie von React in derselben App

Unten finden Sie ein kleines Beispiel für Code, der diesen Fehler verursacht. Andere Beispiele weisen untergeordneten Elementen ebenfalls Klassen zu. Ich kann in der MUI-Dokumentation nichts finden, was andere Verwendungsmöglichkeiten makeStylesund die Möglichkeit zur Verwendung von Lebenszyklusmethoden zeigt.

    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;

Antworten:


152

Hallo, anstatt die Hook-API zu verwenden, sollten Sie die hier erwähnte Komponenten-API höherer Ordnung verwenden

Ich werde das Beispiel in der Dokumentation an Ihre Anforderungen an die Klassenkomponente anpassen

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);

Toll! Ja, die Beispiele zeigen diese Methode nicht. Ich bin allerdings gespannt, wie Sie Ihre "HighOrderComponent" in einer anderen .js-Datei verwenden würden. Sie können "withStyles (styles) (HigherOrderComponent)" verwenden, um einen zu instanziieren. Wie verweisen Sie jedoch auf die Stile in der .js-Datei von HigherOrderComponent? Und passierst du Requisiten einfach auf die übliche Weise?
ThePartyTurtle

4
Ich bin mit diesem Fehler und dem invalid hook callFehler im Kreis herumgelaufen - Danke, dass du mich in die richtige Richtung gebracht hast !!
Kitson

1
@ Jax-p siehe meine Lösung
Matt Weber

4
@VikasKumar Wie kann ich mit diesem Ansatz das App-Thema in meinen Stilen verwenden? Fe senden: {margin: appTheme.spacing (3, 0, 2),},
Sergey Aldoukhov

1
@ Kitson, wahrscheinlich hast du makeStyles() ( styles = makeStyles(theme => ({...})) verwendet . Wenn Sie einen themenabhängigen Stil wünschen, lesen Sie auch meinen vorherigen Kommentar.
Mir-Ismaili

32

Ich habe withStylesstatt verwendetmakeStyle

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)

15

Am Ende haben wir die Verwendung der Klassenkomponenten gestoppt und Funktionskomponenten erstellt, die überuseEffect() die Hooks-API für Lebenszyklusmethoden verwendet wurden . Auf diese Weise können Sie weiterhin makeStyles()mit Lifecycle-Methoden arbeiten, ohne die Komplikation der Erstellung von Komponenten höherer Ordnung hinzufügen zu müssen . Welches ist viel einfacher.

Beispiel:

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
Für Benutzer, die React 16.8 Hooks Update oder höher verwenden, ist der Wechsel zu einer Funktion meiner Meinung nach eine ideale Lösung. In 16.8 können Funktionen auf Status- und Lebenszyklus-Hooks zugreifen.
Tim

4
Ich bin verblüfft, warum dies zu Abstimmungen geführt hat. React hat deutlich gemacht, dass Klassen durch Funktionskomponenten mit Hooks ersetzt werden. reactjs.org/docs/…
Matt Weber

3
Ich habe nicht abgelehnt, aber es ist schwierig, den Anfangszustand mit xhr faul einzustellen, während funktionsbasierte Komponenten verwendet werden. Mit der Klassenkomponente kann ich den Anfangszustand auf das setzen, was ich will, dann Ajax und dann setState verwenden, sobald die Antwort eintrifft. Ich habe überhaupt keine Ahnung, wie ich es mit einer Funktion gut machen soll.
Mlt

1
Sie würden verwenden useEffect. Im obigen Fall setzen Sie den Anfangszustand von userName auf eine leere Zeichenfolge und versichern nach einem API-Aufruf, dass useEffectSie ihn verwenden würden setUserName(response). Ich werde oben ein Beispiel und einen Link zu einem Artikel mit weiteren Informationen zur Verwendung von useEffect für Lebenszyklusmethoden hinzufügen. dev.to/prototyp/…
Matt Weber

3
Dies wird abgelehnt, weil die funktionale Programmierung tatsächliche Anwendungen, die Architektur benötigen, in Mitleidenschaft zieht. Es verstärkt die bereits weit verbreitete Tendenz von js-Programmierern, große Mengen an Spaghetti-Code zu erstellen, die wirklich, wirklich schwer zu lesen / zu befolgen sind und nicht in vernünftige Komponenten aufgeteilt werden können. Wenn die Reaktion auf diese Weise voranschreitet, machen sie einen großen Fehler, und ich werde ihnen dort nicht folgen.
RickyA

2

useStyles ist ein React-Hook, der für die Verwendung in Funktionskomponenten vorgesehen ist und nicht in Klassenkomponenten verwendet werden kann.

Aus Reaktion:

Mit Hooks können Sie Status- und andere Reaktionsfunktionen verwenden, ohne eine Klasse zu schreiben.

Auch sollten Sie useStylesHook in Ihrer Funktion wie aufrufen ;

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

Wenn Sie Hooks verwenden möchten, wird hier Ihre kurze Klassenkomponente in eine Funktionskomponente geändert.

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;

🏓 auf ↓ CodeSandBox ↓

Bearbeiten Reagieren Sie Hooks


-1

Anstatt die Klasse in eine Funktion zu konvertieren, besteht ein einfacher Schritt darin, eine Funktion zu erstellen, die das jsx für die Komponente enthält, die die 'Klassen' verwendet, in Ihrem Fall die <container></container>und diese Funktion dann innerhalb der Rückgabe der Klasse render () aufruft. als Tag. Auf diese Weise verschieben Sie den Hook zu einer Funktion aus der Klasse. Es hat perfekt für mich funktioniert. In meinem Fall war es eine, <table>die ich in eine Funktion - TableStmt außerhalb - verschoben und diese Funktion innerhalb des Renderings als aufgerufen habe<TableStmt/>

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.