Як стилізувати компоненти за допомогою makeStyles і все одно мати методи життєвого циклу в інтерфейсі матеріалу?


118

Я отримую нижченаведену помилку щоразу, коли намагаюся використовувати makeStyles()з компонентом методи життєвого циклу:

Недійсний дзвінок підключення. Гачки можна викликати лише всередині тіла функціонального компонента. Це може статися з однієї з таких причин:

  1. Можливо, у вас є невідповідні версії React та візуалізатора (наприклад, React DOM)
  2. Можливо, ви порушуєте Правила гачків
  3. У вас може бути більше однієї копії React в одному додатку

Нижче наведено невеликий приклад коду, який видає цю помилку. Інші приклади також призначають класи дочірнім предметам. Я не можу знайти в документації MUI нічого, що показує інші способи використання makeStylesта має можливість використовувати методи життєвого циклу.

    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;

Відповіді:


170

Привіт, замість того, щоб використовувати API хука, ти повинен використовувати API компонентів вищого порядку, як згадано тут

Я зміню приклад у документації відповідно до ваших потреб у компоненті класу

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
Я бігав по колу з цією помилкою та invalid hook callпомилкою - Дякуємо, що привели мене у правильному напрямку !!
Кітсон,

1
@ Jax-p see my solution
Matt Weber

4
@VikasKumar За такого підходу, як я можу використовувати тему програми у своїх стилях? Fe submit: {margin: appTheme.spacing (3, 0, 2),},
Сергій Алдухов

1
Дякую. Але проблема! Ви не використовували themeу своєму stylesтілі (@SergeyAldoukhov це вже сказав). Коли я використовую його, я отримую цю помилку: «Не вдається прочитати властивість" X "невизначених» і undefinedце themeточно! Я спробував, withStyles(styles(myDefinedMuiTheme))(...)і це спрацювало правильно.
Мір-Ісмаїлі

1
@Kitson, Можливо, ти використовував makeStyles() ( styles = makeStyles(theme => ({...})) . Крім того, якщо ви хочете залежати від теми, дивіться мій попередній коментар.
Мір-Ісмаїлі

41

Я використовував withStylesзамістьmakeStyle

ЕКС:

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)

19

Що ми в результаті зробили, припиняємо використовувати компоненти класу та створюємо функціональні компоненти, використовуючиuseEffect() з Hooks API для методів життєвого циклу . Це дозволяє продовжувати використовувати makeStyles()методи життєвого циклу, не ускладнюючи створення компонентів вищого порядку . Що набагато простіше.

Приклад:

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
Для людей, які використовують React 16.8 Hooks update або новішу версію, я думаю, що перехід на функцію є ідеальним рішенням. У 16.8 функції можуть отримувати доступ до стану та переключень життєвого циклу.
Тім

5
Мене бентежить, чому це стало проти. React дав зрозуміти, що класи замінюються функціональними компонентами на Hooks. responsejs.org/docs/…
Метт Вебер,

3
Я не голосував проти, але боляче встановлювати початковий стан лінивим способом за допомогою xhr, використовуючи компонент на основі функції. За допомогою компонента класу я можу встановити початковий стан як завгодно, а потім використовувати ajax, а потім setState, як тільки надійде відповідь. Я абсолютно не маю уявлення, як це зробити красиво за допомогою функції.
mlt

1
Ви б використали useEffect. У наведеному вище випадку ви встановлюєте для початкового стану userName порожній рядок, то після завершеного виклику API страхування від useEffectвас буде використовуватися setUserName(response). Я додаю приклад вище та посилання на статтю з додатковою інформацією про використання useEffect для методів життєвого циклу. dev.to/prototyp/…
Метт Вебер,

3
Це голосує за те, що функціональне програмування відсмоктує фактичні програми, які потребують архітектури. Це посилює і без того поширену тенденцію програмістів js робити великі навали коду спагетті, які насправді дуже важко читати / виконувати і неможливо розділити на розумні компоненти. Якщо реакція штовхає таким чином, вони роблять велику помилку, і я не буду слідувати за ними там.
RickyA

2

useStyles - це гачок React, який призначений для використання у функціональних компонентах і не може бути використаний у компонентах класу.

З React:

Хуки дозволяють використовувати стан та інші функції React без написання класу.

Також вам слід викликати useStylesхук всередині вашої функції типу;

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

Якщо ви хочете використовувати хуки, ось ваш короткий компонент класу, змінений на функціональний компонент;

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;

🏓 на ↓ CodeSandBox ↓

Редагувати гачки React


0

Ще одне рішення можна використовувати для компонентів класу - просто перевизначте властивості теми MUI за замовчуванням за допомогою MuiThemeProvider. Це надасть більшу гнучкість у порівнянні з іншими методами - ви можете використовувати більше одного MuiThemeProvider всередині вашого батьківського компонента.

прості кроки:

  1. імпортуйте MuiThemeProvider до компонента вашого класу
  2. імпортуйте createMuiTheme до компонента вашого класу
  3. створити нову тему
  4. оберніть цільовий компонент MUI, який ви хочете стилізувати, за допомогою MuiThemeProvider та власної теми

будь-ласка, ознайомтесь із цим документом для отримання додаткової інформації: 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

Замість перетворення класу у функцію простим кроком було б створити функцію для включення jsx для компонента, який використовує 'класи', у вашому випадку, <container></container>а потім викликати цю функцію всередині повернення класу render () як тег. Таким чином ви пересуваєте гачок до функції з класу. У мене це спрацювало ідеально. У моєму випадку це було те, <table>яке я перемістив до функції - TableStmt зовні і викликав цю функцію всередині візуалізації як<TableStmt/>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.