将Material-UI转换为React中的类 [英] Converting Material-UI to a class in react

查看:46
本文介绍了将Material-UI转换为React中的类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用"Stepper"反应material-ui 组件,但是我很难以类的方式使用它,而不是像它们在预览中那样发挥作用.

I am trying to use the 'Stepper' react material-ui component, but I am having difficulty using it in a class fashion, rather than function as they have in their previews.

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

Here is what I have so far, and it does load but with some problems:

  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网站中的示例代码用作类而不是函数.

I know it's a lot, but I'm simply trying to use the same example code from material-ui website as a class instead of a function..

谢谢您的帮助!

推荐答案

我认为您是在这里清除 this.state.skipped ,因为 this.skipped 不会似乎没有在任何地方宣布.

I think you're wiping out this.state.skipped here, since this.skipped doesn't appear to be declared anywhere.

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

此调用后, this.state.skipped undefined ,因此调用 this.state.skipped.has(...)炸毁.

After this call, this.state.skipped is undefined, so calling this.state.skipped.has(...) blows up.

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

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

Another source of trouble might be a scope issue that arises from the way your click handlers are declared and attached, e.g. onClick={this.handleNext}.

TLDR:尝试 onClick = {()=>代替this.handleNext()} .

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

In javascript the scope (what this refers to) inside a method call is generally set to the object on which it was called.

因此,如果您调用 this.handleNext(),则在 handleNext 中对 this 的引用将成为您的组件.

So if you call this.handleNext(), references to this inside handleNext will be your component, as you expect.

但是,如果您选择这样做:

However, if instead you do:

const {handleNext} = this;
handleNext();

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

The this reference may not be what you expect, because the method wasn't invoked as a method on your component. It was invoked as a standalone function, detached from your component. And this is effectively what happens when you pass an event handler down to another component. Inside the child component (the button, for example), your handler is just a function passed in as a prop, detached from your component:

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

有几种方法可以解决此问题,但最简单的两种方法是:

There are several ways to fix this, but the two most straightforward are:

  1. 声明一个新函数来调用组件上的处理程序:

onClick={ () => this.handleNext() }

  1. 为处理程序添加一个箭头函数,因为箭头函数会自动采用声明它们的父级作用域.所以代替这个:

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

执行此操作:

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

希望这会有所帮助.抱歉,太长了.试一试,让我知道.

Hope this helps. Sorry it's so long. Give it a shot and let me know.

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

Side note: you can do both of these in a single call:

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

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

这篇关于将Material-UI转换为React中的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆