将Material-UI转换为React中的类

时间:2019-09-20 04:59:31

标签: reactjs material-ui

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

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

  1. 出现的文本是“未知步骤”,这意味着未正确调用函数“ getStepContent”
  2. 每次单击“下一步”按钮时,都会给我一个错误消息:“无法读取未定义的属性”“具有”似乎几乎把我所有的函数都弄乱了。。

这是我的代码:

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 个答案:

答案 0 :(得分:0)

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

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

此呼叫后,this.state.skippedundefined,因此呼叫this.state.skipped.has(...)会爆炸。

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


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

TLDR:请尝试使用onClick={() => this.handleNext()}

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

因此,如果您调用this.handleNext(),则在this中对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
})