반응형
참고
- 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을 순차적으로 변경한다.
현재 step은 0 ~ 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
failedStep을 useState로 선언하고 isStepFailed를 수정하자.
const [failedStep, setFailedStep] = useState(-1);
const isStepFailed = (step) => {
return step === failedStep;
};
startProgress는 다음과 같이 수정한다.
비동기 함수가 실패하는 step을 failed로 처리하였다.
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;
}
failedStep이 2가 되면서 Step 2에 Alert 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;
반응형
'개발 > React' 카테고리의 다른 글
리액트 - react-diff-viewer-continued로 텍스트 비교하기 (Compare Text with Diff Viewer) (1) | 2024.01.31 |
---|---|
리액트 - html2pdf로 PDF 다운로드하기 (0) | 2024.01.28 |
리액트 - 리덕스로 로그인 상태 관리하기 (Managing Login State with Redux) (0) | 2024.01.22 |
리액트 - Toast UI 에디터로 이미지를 포함한 깃허브 마크다운 저장하기 (Toast UI Markdown Editor) (0) | 2024.01.17 |
리액트 - 캡처한 이미지 여러 개 업로드하기 (Upload Captured Images to GitHub) (0) | 2024.01.17 |
댓글