본문 바로가기
개발/React

React Material - Stepper로 워크 플로우 관리하기 (Managing Workflows with Mui Stepper)

by 피로물든딸기 2024. 1. 24.
반응형

리액트 전체 링크

 

참고

- https://mui.com/material-ui/react-stepper/

 

아래 결과는 링크에서 확인할 수 있다.

 

Material UI Stepper를 이용해서 워크 플로우를 관리해 보자.

 

시작 코드는 다음과 같다.

import React from "react";
import Box from "@mui/material/Box";
import Stepper from "@mui/material/Stepper";
import Step from "@mui/material/Step";
import StepLabel from "@mui/material/StepLabel";
import Typography from "@mui/material/Typography";

const steps = ["Step 0", "Step 1", "Step 2", "Step 3"];

const MyStepper = () => {
  const isStepFailed = (step) => {
    return step === -1;
  };

  return (
    <Box sx={{ width: "60%", m: 3 }}>
      <Stepper activeStep={-1}>
        {steps.map((label, index) => {
          const labelProps = {};
          if (isStepFailed(index)) {
            labelProps.optional = (
              <Typography variant="caption" color="error">
                Alert message
              </Typography>
            );

            labelProps.error = true;
          }

          return (
            <Step key={label}>
              <StepLabel {...labelProps}>{label}</StepLabel>
            </Step>
          );
        })}
      </Stepper>
    </Box>
  );
};

export default MyStepper;


구현

 

먼저 임의의 비동기 함수를 만들자. 

tempDelay는 time만큼 delay가 발생하고 주어진 value를 return하는 함수다.

  const tempDelay = async (time, value) => {
    await new Promise((resolve) => setTimeout(resolve, time));
    return value;
  };

 

startProgress 함수를 추가하여 activeStep을 순차적으로 변경한다.

현재 step0 ~ 3이기 때문에 마지막 step에 check 표시를 하기 위해 setActiveStep(4)가 필요하다.

  const [activeStep, setActiveStep] = useState(-1);

...

  const startProgress = async () => {
    setActiveStep(0);
    let step0 = await tempDelay(2000, true);

    setActiveStep(1);
    let step1 = await tempDelay(2000, true);

    setActiveStep(2);
    let step2 = await tempDelay(2000, true);

    setActiveStep(3);
    let step3 = await tempDelay(2000, true);

    setActiveStep(4);  
  };

 

startProgress를 실행할 버튼을 추가하고 Stepper의 activeStep을 useState로 선언한 변수로 할당한다.

  <Button
    variant="outlined"
    color="secondary"
    sx={{ m: 2 }}
    onClick={startProgress}
  >
    START
  </Button>
  <Stepper activeStep={activeStep}>

 

이제 START 버튼을 눌러보자.

 

여기까지 코드는 다음과 같다.

import React, { useState } from "react";
import Box from "@mui/material/Box";
import Stepper from "@mui/material/Stepper";
import Step from "@mui/material/Step";
import StepLabel from "@mui/material/StepLabel";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";

const steps = ["Step 0", "Step 1", "Step 2", "Step 3"];

const MyStepper = () => {
  const [activeStep, setActiveStep] = useState(-1);

  const isStepFailed = (step) => {
    return step === -1;
  };

  const tempDelay = async (time, value) => {
    await new Promise((resolve) => setTimeout(resolve, time));
    return value;
  };

  const startProgress = async () => {
    setActiveStep(0);
    let step0 = await tempDelay(2000, true);

    setActiveStep(1);
    let step1 = await tempDelay(2000, true);

    setActiveStep(2);
    let step2 = await tempDelay(2000, true);

    setActiveStep(3);
    let step3 = await tempDelay(2000, true);

    setActiveStep(4);
  };

  return (
    <Box sx={{ width: "60%", m: 3 }}>
      <Button
        variant="outlined"
        color="secondary"
        sx={{ m: 2 }}
        onClick={startProgress}
      >
        START
      </Button>
      <Stepper activeStep={activeStep}>
        {steps.map((label, index) => {
          const labelProps = {};
          if (isStepFailed(index)) {
            labelProps.optional = (
              <Typography variant="caption" color="error">
                Alert message
              </Typography>
            );

            labelProps.error = true;
          }

          return (
            <Step key={label}>
              <StepLabel {...labelProps}>{label}</StepLabel>
            </Step>
          );
        })}
      </Stepper>
    </Box>
  );
};

export default MyStepper;

Error Step

 

failedStepuseState로 선언하고 isStepFailed를 수정하자.

  const [failedStep, setFailedStep] = useState(-1);
  
  const isStepFailed = (step) => {
    return step === failedStep;
  };

 

startProgress는 다음과 같이 수정한다.

비동기 함수가 실패하는 stepfailed로 처리하였다.

  const startProgress = async () => {
    setActiveStep(0);
    let step0 = await tempDelay(2000, true);
    if(step0 === false) {    
      setFailedStep(0);
      return;
    }

    ... 
  };

 

이제 step2의 값이 false가 되도록 해보자.

    let step2 = await tempDelay(2000, false);
    if(step2 === false) {
      setFailedStep(2);
      return;
    }

 

failedStep2가 되면서 Step 2Alert Message가 나타나게 된다.

 

전체 코드는 다음과 같다.

import React, { useState } from "react";
import Box from "@mui/material/Box";
import Stepper from "@mui/material/Stepper";
import Step from "@mui/material/Step";
import StepLabel from "@mui/material/StepLabel";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";

const steps = ["Step 0", "Step 1", "Step 2", "Step 3"];

const MyStepper = () => {
  const [activeStep, setActiveStep] = useState(-1);
  const [failedStep, setFailedStep] = useState(-1);
  
  const isStepFailed = (step) => {
    return step === failedStep;
  };

  const tempDelay = async (time, value) => {
    await new Promise((resolve) => setTimeout(resolve, time));
    return value;
  };

  const startProgress = async () => {
    setActiveStep(0);
    let step0 = await tempDelay(2000, true);
    if(step0 === false) {    
      setFailedStep(0);
      return;
    }

    setActiveStep(1);
    let step1 = await tempDelay(2000, true);
    if(step1 === false) {    
      setFailedStep(1);
      return;
    }

    setActiveStep(2);
    let step2 = await tempDelay(2000, false);
    if(step2 === false) {
      setFailedStep(2);
      return;
    }

    setActiveStep(3);
    let step3 = await tempDelay(2000, true);
    if(step3 === false) {
      setFailedStep(3);
      return;
    }

    setActiveStep(4);   
  };

  return (
    <Box sx={{ width: "60%", m: 3 }}>
      <Button
        variant="outlined"
        color="secondary"
        sx={{ m: 2 }}
        onClick={startProgress}
      >
        START
      </Button>
      <Stepper activeStep={activeStep}>
        {steps.map((label, index) => {
          const labelProps = {};
          if (isStepFailed(index)) {
            labelProps.optional = (
              <Typography variant="caption" color="error">
                Alert message
              </Typography>
            );

            labelProps.error = true;
          }

          return (
            <Step key={label}>
              <StepLabel {...labelProps}>{label}</StepLabel>
            </Step>
          );
        })}
      </Stepper>
    </Box>
  );
};

export default MyStepper;
반응형

댓글