Làm cách nào để tạo kiểu cho các thành phần bằng makeStyles và vẫn có các phương thức vòng đời trong Material UI?


117

Tôi gặp lỗi dưới đây bất cứ khi nào tôi cố gắng sử dụng makeStyles()với một thành phần có các phương thức vòng đời:

Cuộc gọi hook không hợp lệ. Hook chỉ có thể được gọi bên trong phần thân của một thành phần hàm. Điều này có thể xảy ra vì một trong những lý do sau:

  1. Bạn có thể có các phiên bản React và trình kết xuất không khớp (chẳng hạn như React DOM)
  2. Bạn có thể đang vi phạm Quy tắc của Hooks
  3. Bạn có thể có nhiều hơn một bản sao của React trong cùng một ứng dụng

Dưới đây là một ví dụ nhỏ về mã tạo ra lỗi này. Các ví dụ khác cũng chỉ định các lớp cho các mục con. Tôi không thể tìm thấy bất kỳ điều gì trong tài liệu của MUI cho thấy các cách khác để sử dụng makeStylesvà khả năng sử dụng các phương pháp vòng đời.

    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;

Câu trả lời:


170

Xin chào, thay vì sử dụng hook API, bạn nên sử dụng API thành phần bậc cao hơn như đã đề cập ở đây

Tôi sẽ sửa đổi ví dụ trong tài liệu để phù hợp với nhu cầu của bạn đối với thành phần lớp

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
Tôi đã chạy vòng quanh với lỗi này và invalid hook calllỗi - Cảm ơn vì đã đưa tôi đi đúng hướng !!
Kitson

1
@ Jax-p thấy giải pháp của tôi
Matt Weber

4
@VikasKumar Với cách tiếp cận này, tôi có thể sử dụng chủ đề ứng dụng theo phong cách của mình như thế nào? Fe nộp: {margin: appTheme.spacing (3, 0, 2),},
Sergey Aldoukhov

1
Cảm ơn. Nhưng một vấn đề! Bạn đã không sử dụng themetrong stylescơ thể của mình (@SergeyAldoukhov đã nói điều này rồi). Khi tôi sử dụng nó, tôi gặp lỗi này: "Không thể đọc thuộc tính 'X' của undefined" và chính xác undefinedlà như themevậy! Tôi đã thử withStyles(styles(myDefinedMuiTheme))(...)và nó hoạt động chính xác.
Mir-Ismaili

1
@Kitson, Có thể bạn đã sử dụng makeStyles() ( styles = makeStyles(theme => ({...})) . Ngoài ra, nếu bạn muốn phong cách phụ thuộc vào chủ đề, hãy xem nhận xét trước của tôi.
Mir-Ismaili

41

Tôi đã sử dụng withStylesthay vìmakeStyle

VÍ DỤ :

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

Những gì chúng tôi đã kết thúc là ngừng sử dụng các thành phần lớp và tạo các Thành phần chức năng, sử dụnguseEffect() từ API Hooks cho các phương thức vòng đời . Điều này cho phép bạn vẫn sử dụng makeStyles()với các Phương thức Vòng đời mà không cần thêm phức tạp khi tạo các Thành phần Thứ tự Cao hơn . Mà đơn giản hơn nhiều.

Thí dụ:

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
Đối với những người đang sử dụng bản cập nhật React 16.8 Hooks trở lên, tôi nghĩ chuyển sang một hàm là một giải pháp lý tưởng. Trong 16.8 các chức năng có thể truy cập các móc trạng thái và vòng đời.
Tim

5
Tôi bối rối tại sao điều này lại nhận được sự phản đối. React đã nói rõ rằng các lớp đang được thay thế bằng các thành phần chức năng với Hooks. reactjs.org/docs/…
Matt Weber

3
Tôi đã không ủng hộ, nhưng thật khó để đặt trạng thái ban đầu theo cách lười biếng bằng cách sử dụng xhr trong khi sử dụng thành phần dựa trên hàm. Với thành phần lớp, tôi có thể đặt trạng thái ban đầu thành bất kỳ thứ gì tôi muốn, sau đó sử dụng ajax rồi setState khi phản hồi đến. Tôi hoàn toàn không biết làm thế nào để làm điều đó độc đáo với một hàm.
mlt

1
Bạn sẽ sử dụng useEffect. Trong trường hợp trên, bạn đang đặt trạng thái ban đầu của userName thành một chuỗi trống, sau đó sau khi thực hiện xong một lệnh gọi API, useEffectbạn sẽ sử dụng setUserName(response). Tôi sẽ thêm một ví dụ ở trên và một liên kết đến một artical với nhiều thông tin hơn về cách sử dụng useEffect cho các phương thức vòng đời. dev.to/prototyp/…
Matt Weber

3
Điều này đang bị bỏ phiếu vì lập trình chức năng không phù hợp với các ứng dụng thực tế cần kiến ​​trúc. Nó nâng cao xu hướng đã gia tăng của các lập trình viên js để tạo ra một loạt mã spaghetti thực sự, thực sự khó đọc / thực sự khó đọc / theo dõi và không thể được chia thành các thành phần hợp lý. Nếu phản ứng xảy ra theo cách này, họ đang mắc một sai lầm lớn, và tôi sẽ không theo dõi họ ở đó.
RickyA

2

useStyles là một React hook được sử dụng trong các thành phần chức năng và không thể được sử dụng trong các thành phần lớp.

Từ React:

Hooks cho phép bạn sử dụng trạng thái và các tính năng khác của React mà không cần viết một lớp.

Ngoài ra, bạn nên gọi useStyleshook bên trong hàm của mình như;

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

Nếu bạn muốn sử dụng hook, đây là thành phần lớp ngắn gọn của bạn được thay đổi thành thành phần chức năng;

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;

🏓 trên ↓ CodeSandBox ↓

Chỉnh sửa móc React


0

Một giải pháp khác có thể được sử dụng cho các thành phần lớp - chỉ cần ghi đè các thuộc tính MUI Theme mặc định bằng MuiThemeProvider. Điều này sẽ mang lại sự linh hoạt hơn so với các phương pháp khác - bạn có thể sử dụng nhiều MuiThemeProvider bên trong thành phần mẹ của mình.

các bước đơn giản:

  1. nhập MuiThemeProvider vào thành phần lớp của bạn
  2. nhập createMuiTheme vào thành phần lớp của bạn
  3. tạo chủ đề mới
  4. bọc thành phần MUI mục tiêu mà bạn muốn tạo kiểu với MuiThemeProvider và chủ đề tùy chỉnh của bạn

vui lòng kiểm tra tài liệu này để biết thêm chi tiết: 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

Thay vì chuyển đổi lớp thành một hàm, một bước dễ dàng sẽ là tạo một hàm để bao gồm jsx cho thành phần sử dụng 'các lớp', trong trường hợp của bạn <container></container>, sau đó gọi hàm này bên trong trả về của lớp render () như một thẻ. Bằng cách này, bạn đang chuyển hook sang một hàm từ lớp. Nó làm việc hoàn hảo cho tôi. Trong trường hợp của tôi, đó là một hàm <table>mà tôi đã chuyển sang một hàm- TableStmt bên ngoài và gọi hàm này bên trong kết xuất là<TableStmt/>

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.