在 React 中将 Material-UI 转换为类

IT技术 reactjs material-ui
2021-05-10 04:44:33

我正在尝试使用“Stepper”react material-ui组件,但我很难以课堂方式使用它,而不是像他们在预览中那样使用它。

这是我到目前为止所拥有的,它确实加载了但有一些问题:

  1. 出现的文本是“未知步骤”,这意味着函数“getStepContent”没有被正确调用
  2. 每次我点击“下一步”按钮时,它都会给我一条错误消息:“无法读取未定义的属性 'has'”似乎我几乎所有的函数调用都搞砸了..

这是我的代码:

import React, { Component } from "react";
import "./CharacterCreate.css";
import PropTypes from 'prop-types';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import Typography from '@material-ui/core/Typography';
import Box from '@material-ui/core/Box';

import { makeStyles } from '@material-ui/core/styles';
import Stepper from '@material-ui/core/Stepper';
import Step from '@material-ui/core/Step';
import StepLabel from '@material-ui/core/StepLabel';
import Button from '@material-ui/core/Button';


export default class CharacterCreate extends Component {

  constructor(props) {
    super(props);
    this.state = {
      activeStep: 0,
      skipped :new Set()
    };
    this.handleNext = this.handleNext.bind(this);
    this.isStepSkipped = this.isStepSkipped.bind(this);
  }

  getSteps() {
    return ['Select campaign settings', 'Create an ad group', 'Create an ad'];
  }

  getStepContent(step) {
    switch (step) {
      case 0:
        return 'Select campaign settings...';
      case 1:
        return 'What is an ad group anyways?';
      case 2:
        return 'This is the bit I really care about!';
      default:
        return 'Unknown step';
    }
  }

  isStepOptional(step) {
    return step === 1;
  }

  isStepSkipped(step) {
    return this.state.skipped.has(step);
  }

  handleNext() {
    let newSkipped = this.skipped;
    if (this.isStepSkipped(this.activeStep)) {
      newSkipped = new Set(newSkipped.values());
      newSkipped.delete(this.activeStep);
    }

    this.setState({activeStep: prevActiveStep => prevActiveStep + 1})
    this.setState({skipped: this.skipped});
  }

  handleBack() {
    this.setState({activeStep: prevActiveStep => prevActiveStep - 1})
  }

  handleSkip() {
    if (!this.isStepOptional(this.activeStep)) {
      // You probably want to guard against something like this,
      // it should never occur unless someone's actively trying to break something.
      throw new Error("You can't skip a step that isn't optional.");
    }

    this.setState({activeStep: prevActiveStep => prevActiveStep + 1})
    this.setSkipped(prevSkipped => {
      const newSkipped = new Set(prevSkipped.values());
      newSkipped.add(this.activeStep);
      return newSkipped;
    });
  }

  handleReset() {
    this.setState({activeStep: 0})
  }


render() {

  const steps = this.getSteps();

  return (
    <div className="root">
      <Stepper activeStep={this.activeStep}>
        {steps.map((label, index) => {
          const stepProps = {};
          const labelProps = {};
          if (this.isStepOptional(index)) {
            labelProps.optional = <Typography variant="caption">Optional</Typography>;
          }
          if (this.isStepSkipped(index)) {
            stepProps.completed = false;
          }
          return (
            <Step key={label} {...stepProps}>
              <StepLabel {...labelProps}>{label}</StepLabel>
            </Step>
          );
        })}
      </Stepper>
      <div>
        {this.activeStep === steps.length ? (
          <div>
            <Typography className="instructions">
              All steps completed - you&apos;re finished
            </Typography>
            <Button onClick={this.handleReset} className="button">
              Reset
            </Button>
          </div>
        ) : (
          <div>
            <Typography className="instructions">{this.getStepContent(this.activeStep)}</Typography>
            <div>
              <Button disabled={this.activeStep === 0} onClick={this.handleBack} className="button">
                Back
              </Button>
              {this.isStepOptional(this.activeStep) && (
                <Button
                  variant="contained"
                  color="primary"
                  onClick={this.handleSkip}
                  className="button"
                >
                  Skip
                </Button>
              )}

              <Button
                variant="contained"
                color="primary"
                onClick={this.handleNext}
                className="button"
              >
                {this.activeStep === steps.length - 1 ? 'Finish' : 'Next'}
              </Button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

}

我知道它很多,但我只是尝试将 material-ui 网站中的相同示例代码用作类而不是函数。

谢谢您的帮助!

1个回答

我认为您正在清除this.state.skipped这里,因为this.skipped似乎没有在任何地方声明。

this.setState({skipped: this.skipped});

在这个调用之后,this.state.skippedis undefined,所以调用this.state.skipped.has(...)爆炸了。

我怀疑你打算使用this.state.skipped.


另一个麻烦来源可能是由您的点击处理程序的声明和附加方式引起的范围问题,例如onClick={this.handleNext}.

TLDR:试试吧onClick={() => this.handleNext()}

在 javascript 中,this方法调用内的范围(指的是什么)通常设置为调用它的对象。

因此,如果您调用this.handleNext(),对thisinside 的引用handleNext将成为您的组件,正如您所期望的那样。

但是,如果您这样做:

const {handleNext} = this;
handleNext();

this参考可能不是你所期望的,因为该方法没有被引用为您的组件上的方法。它是作为独立函数调用的,与您的组件分离。这实际上是将事件处理程序传递给另一个组件时发生的情况。在子组件(例如按钮)内部,您的处理程序只是一个作为 prop 传入的函数,与您的组件分离:

// inside the button component
const {onClick} = this.props;
onClick(); // no scope; detached from your component

有多种方法可以解决此问题,但最直接的两种方法是:

  1. 声明一个调用组件上的处理程序的新函数:
onClick={ () => this.handleNext() }
  1. 使您的处理程序成为箭头函数,因为箭头函数会自动采用声明它们的父作用域。所以而不是这个:
handleNext() {
  let newSkipped = this.skipped;
  ...

做这个:

handleNext = () => {
  let newSkipped = this.skipped;

希望这可以帮助。抱歉这么长。试一试,让我知道。


旁注:您可以在一次调用中完成这两项操作:

this.setState({activeStep: prevActiveStep => prevActiveStep + 1})
this.setState({skipped: this.skipped});
this.setState({
  activeStep: prevActiveStep => prevActiveStep + 1,
  skipped: this.state.skipped
})