Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
415 views
in Technique[技术] by (71.8m points)

javascript - 如何使用React管理多步骤表单?(How to manage a multi-step form with React?)

Here is the code of my multistep form:

(这是我的多步骤表单的代码:)

import clsx from 'clsx';
import React from 'react';
import PropTypes from 'prop-types';
import { makeStyles, withStyles } from '@material-ui/styles';
import Step from '@material-ui/core/Step';
import Stepper from '@material-ui/core/Stepper';
import StepLabel from '@material-ui/core/StepLabel';
import StepConnector from '@material-ui/core/StepConnector';
import { Container, Row, Col, Button } from 'react-bootstrap';

import Description from '@material-ui/icons/Description';
import AccountCircle from '@material-ui/icons/AccountCircle';
import DirectionsCar from '@material-ui/icons/DirectionsCar';

import Step1 from '../components/Step1';
import Step2 from '../components/Step2';
import Step3 from '../components/Step3';

const styles = () => ({
  root: {
    width: '90%',
  },
  button: {
    marginRight: '0 auto',
  },
  instructions: {
    marginTop: '0 auto',
    marginBottom: '0 auto',
  },
});

const ColorlibConnector = withStyles({ 
  alternativeLabel: {
    top: 22,
  },
  active: {
    '& $line': {
      backgroundColor: '#00b0ff',
    },
  },
  completed: {
    '& $line': {
      backgroundColor: '#00b0ff',
    },
  },
  line: {
    height: 3,
    border: 0,
    backgroundColor: '#eaeaf0',
    borderRadius: 1,
  },
})(StepConnector);

const useColorlibStepIconStyles = makeStyles({
  root: {
    backgroundColor: '#ccc',
    zIndex: 1,
    color: '#fff',
    width: 50,
    height: 50,
    display: 'flex',
    borderRadius: '50%',
    justifyContent: 'center',
    alignItems: 'center',
  },
  active: {
    backgroundColor: '#00b0ff',
    boxShadow: '0 4px 10px 0 rgba(0,0,0,.25)',
  },
  completed: {
    backgroundColor: '#00b0ff',
  },
});

function ColorlibStepIcon(props) {
  const classes = useColorlibStepIconStyles();
  const { active, completed } = props;

  const icons = {
    1: <AccountCircle />,
    2: <DirectionsCar />,
    3: <Description />,
  };

  return (
    <div
      className={clsx(classes.root, {
        [classes.active]: active,
        [classes.completed]: completed,
      })}
    >
      {icons[String(props.icon)]}
    </div>
  );
}

function getSteps() {
  return ['Dati Assicurato', 'Dati Veicolo', 'Dati Assicurazione'];
}

function getStepContent(step) {
  switch (step) {
    case 0:
      return <Step1/>;
    case 1:
      return <Step2/>;
    case 2:
      return <Step3/>;;
    default:
      return 'Unknown step';
  }
}

class HorizontalLinearStepper extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      activeStep: 0,
      agencyData: {}
    };
  }

  static propTypes = {
    classes: PropTypes.object,
  };

  isStepOptional = step => {
    return step === 1;
  };

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

  handleBack = () => {
    const { activeStep } = this.state;
    this.setState({
      activeStep: activeStep - 1,
    });
  };

  handleReset = () => {
    this.setState({
      activeStep: 0,
    });
  };

  logout = () => {
    localStorage.clear();
    this.props.history.push('/');
  }

  render() {
    const { classes } = this.props;
    const steps = getSteps();
    const { activeStep } = this.state;

    return (
      <Container fluid>
        <div className={classes.root}>
          <Stepper alternativeLabel activeStep={activeStep} connector={<ColorlibConnector />}>
            {steps.map((label, index) => {
              const props = {};

              return (
                <Step key={label} {...props}>
                  <StepLabel StepIconComponent={ColorlibStepIcon}>{label}</StepLabel>
                </Step>
              );
            })}
          </Stepper>

          <div>
            {activeStep === steps.length ? (
              <div style={{textAlign: 'center'}}>
                <h1 style={{textAlign: 'center', paddingTop: 100, color: '#7fc297'}}>
                  TERMINATO
                </h1>
                <h4 style={{textAlign: 'center', paddingTop: 50}}>
                  Tutti gli step sono stati completati con successo! 
                </h4>  
                <h4 style={{textAlign: 'center'}}>  
                  Procedi con la generazione del QR Code.
                </h4>
                <Row style={{marginTop: '40px'}} className='justify-content-center align-items-center text-center'>
                  <Col md={{span: 3}}>
                    <Button 
                      style={{borderRadius: 30, borderWidth: 0, height: 50, width: 150, backgroundColor: '#f32a19', borderColor: '#f32a19'}}
                      disabled={activeStep === 0} 
                      onClick={this.handleReset} 
                    >
                      Annulla
                    </Button>
                  </Col>
                  <Col md={{span: 3}}>
                    <Button
                        style={{borderRadius: 30, borderWidth: 0, height: 50, width: 150, backgroundColor: '#00b0ff'}}
                        onClick={() => console.log('Click')}
                      >
                      Procedi
                    </Button>
                  </Col>
                </Row>
              </div>
            ) : 
            (
              <Container style={{}}>
                <h2 className={classes.instructions}>{getStepContent(activeStep)}</h2>
                <Row className='justify-content-center align-items-center text-center'>
                  <Col md={{span: 3}}>
                    <Button 
                      style={{marginTop: 10, backgroundColor: 'gold', borderRadius: 30, borderWidth: 0, height: 50, width: 150}}
                      disabled={activeStep === 0} 
                      onClick={this.handleBack} 
                    >
                      Indietro
                    </Button>
                  </Col>
                  <Col md={{span: 3}}>
                    {
                      activeStep === steps.length - 1 ?
                      <Button
                        style={{marginTop: 10, borderRadius: 30, borderWidth: 0, height: 50, width: 150, backgroundColor: '#7fc297'}}
                        onClick={this.handleNext}
                      >
                      Finito
                      </Button>
                      :
                      <Button
                        style={{marginTop: 10, backgroundColor: '#00b0ff', borderRadius: 30, borderWidth: 0, height: 50, width: 150}}
                        onClick={this.handleNext}
                      >
                      Avanti
                      </Button>
                    }
                  </Col>
                </Row>
              </Container>
            )}
          </div>
        </div>
      </Container>
    );
  }
}

export default withStyles(styles)(HorizontalLinearStepper);

It is composed of three steps and at each step I ask for many data.

(它由三个步骤组成,在每个步骤中,我要求提供许多数据。)

This is the code of one of the Step (they are all the same, the difference are the contents of the input fields):

(这是“ Step ”之一的代码(它们都相同,不同之处在于输入字段的内容):)

import React from 'react';
import { Container, Row, Col, Form } from 'react-bootstrap';

export default function Step2(props) {

  return(
    <Container>
      <Row style={{marginTop: '30px'}} className='h-100 justify-content-center align-items-center'>
        <Col md={{ span: 6 }} className='text-center my-auto'>
          <h3 style={{marginBottom: '1rem'}}>Dati Veicolo</h3>
          <Form>
            <Form.Row>
              <Form.Group as={Col}>
                <Form.Control
                  type='text' 
                  placeholder='Marca' 
                  required
                />
              </Form.Group>
              <Form.Group as={Col}>
                <Form.Control
                  type='text' 
                  placeholder='Targa' 
                  required
                />
              </Form.Group>
            </Form.Row>
            <Form.Group>
              <Form.Control
                type='text' 
                placeholder='Paese immatricolazione' 
                required
              />
            </Form.Group>
            <h6 style={{marginBottom: '1rem'}}>Possiede un rimorchio?</h6>              
            <Form.Group>
              <Form.Control
                type='text' 
                placeholder='Targa'
              />
            </Form.Group>
            <Form.Group>
              <Form.Control
                type='text' 
                placeholder='Paese immatricolazione'
              />
            </Form.Group>
          </Form>
        </Col>
      </Row>
    </Container>
  );
}

What I need to do is to check for errors at each step before the users pass to the following one, so that they can start fulfilling the second step of the form only in the case they have completed the first step correctly, and so on ... How can I do this check step by step?

(我需要做的是在用户转到下一个步骤之前检查每个步骤的错误,以便仅在正确完成第一步之后,他们才可以开始执行表单的第二步,依此类推。 ..如何逐步检查?)

Moreover how can I collect all the data that I ask for in the main component of the form so that I can work with all those data after the users have finished fulfilling the whole form?

(此外,我如何收集表单主要部分中要求的所有数据,以便在用户完成整个表单后可以处理所有这些数据?)

At this <a href="https://stackoom.com/link/aHR0cHM6Ly9jb2Rlc2F


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I would use a routing that points to the same component so you could store the old form in either your state/reducer/localStorage (in fact anything you want) and once the current step is ok I would simply navigate the user to the next one.

(我将使用指向同一组件的路由,以便将旧表单存储在state / reducer / localStorage(实际上是您想要的任何内容)中,一旦当前步骤确定,我将简单地将用户导航到下一个表单。)

I have made a demo codesandbox with this logic.

(我已经用这种逻辑制作了一个演示codeandbox 。)

I hope it helps

(希望对您有所帮助)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...