makeStylesを使用してコンポーネントのスタイルを設定し、マテリアルUIにライフサイクルメソッドを含めるにはどうすればよいですか?


117

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 @私の解決策を参照
マット・ウェーバー

4
@VikasKumarこのアプローチでは、自分のスタイルでアプリのテーマをどのように使用できますか?Fe送信:{マージン:appTheme.spacing(3、0、2)、}、
SergeyAldoukhov19年

1
ありがとう。しかし、問題があります!あなたはthemeあなたのstyles体で使用しませんでした(@SergeyAldoukhovはすでにこれを言っています)。私はそれを使用すると、私はこのエラーを取得する:「未定義のプロパティ『X』を読み込めません」undefinedありtheme、正確に!試してみましたがwithStyles(styles(myDefinedMuiTheme))(...)、正しく動作しました。
Mir-Ismaili

1
@ Kitson、おそらくあなたはmakeStyles() styles = makeStyles(theme => ({...})を使用しましたまた、テーマに依存したスタイルが必要な場合は、以前のコメントを参照してください。
Mir-Ismaili

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)

18

最終的に行ったことは、クラスコンポーネントの使用を停止し、ライフサイクルメソッドのHooksAPIを使用useEffect()して機能コンポーネントを作成しました。これにより、高次コンポーネントを作成するという複雑さを追加することなく、ライフサイクルメソッドで引き続き使用できます。これははるかに簡単です。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は、クラスがフックを備えた機能コンポーネントに置き換えられていることを明確にしています。 reactjs.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;

🏓on↓CodeSandBox↓

Reactフックを編集する


0

別の1つのソリューションをクラスコンポーネントに使用できます。デフォルトのMUIテーマプロパティをMuiThemeProviderでオーバーライドするだけです。これにより、他のメソッドと比較して柔軟性が向上します。親コンポーネント内で複数のMuiThemeProviderを使用できます。

簡単な手順:

  1. MuiThemeProviderをクラスコンポーネントにインポートします
  2. createMuiThemeをクラスコンポーネントにインポートします
  3. 新しいテーマを作成する
  4. MuiThemeProviderとカスタムテーマでスタイルを設定するターゲットMUIコンポーネントをラップします

詳細については、このドキュメントを確認してください: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/>

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.