【发布时间】:2020-12-30 14:20:56
【问题描述】:
我正在尝试使用 React 钩子使 2 个组件与它们的父组件状态同步。 我使用 horizontal 和 vertical stepper 作为 Material UI 中的 2 个独立组件,它们的父类具有 stepper 的内容和它们的状态 应该分享。 我使用 horizontal 和 vertical stepper 的原因是为了让 UI 尽可能响应。
我遇到的问题是,当activeStep 增加一个组件(即水平步进器)时,根据我对组件安装生命周期的理解。调用 render 方法,Activestep 递增并反映在 dom 中。但它只体现在水平步进器上。更改仅在水平步进器组件中传播。在导航 vertical stepper 组件时,它会返回钩子的初始状态,该状态最初设置为 0。
我正在尝试使 Horizontal 和 Vertical stepper 与 stepperContent 中的 activeStep 同步,并且状态应该在两个组件中传播。
我的问题是
如何使它们与 stepperContent 有状态功能组件中的activeState 同步?
steppertContent.JSX
import { makeStyles } from "@material-ui/core/styles";
import { useState, useEffect } from "react";
export const useVerticalStyles = makeStyles((theme) => ({
root: {
width: "100%",
},
button: {
marginTop: theme.spacing(1),
marginRight: theme.spacing(1),
},
actionsContainer: {
marginBottom: theme.spacing(2),
},
resetContainer: {
padding: theme.spacing(3),
},
}));
export const useHorizontalStyles = makeStyles((theme) => ({
root: {
width: "100%",
},
backButton: {
marginRight: theme.spacing(1),
},
instructions: {
marginTop: theme.spacing(1),
marginBottom: theme.spacing(1),
},
}));
export const StepperContent = () => {
const [activeStep, setActiveStep] = useState(0);
useEffect(() => {
console.log(activeStep);
}, [activeStep]);
// console.log(activeStep);
const handleNext = () => {
setActiveStep((prevActiveStep) => prevActiveStep + 1);
};
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
};
const handleReset = () => {
setActiveStep(0);
};
return { activeStep, handleNext, handleBack, handleReset };
};
export const getSteps = () => {
return [
"ACCOUNT SETUP",
"PERSONAL INFORMATION",
"CONTACT INFORMATION",
"FAMILY INFORMATION",
"SCHOOL INFORMATION",
"ADMISSION INFORMATION",
"SUBMIT INFORMATION",
];
};
export const getStepContent = (stepIndex) => {
switch (stepIndex) {
case 0:
return "CREATE YOUR ACCOUNT";
case 1:
return "What is an ad group anyways?";
case 2:
return "This is the bit I really care about!";
default:
return "Unknown stepIndex";
}
};
horizontalFormStepper.JSX
import React from "react";
import {
Stepper,
Step,
StepLabel,
Button,
Typography,
} from "@material-ui/core/";
import {
getStepContent,
getSteps,
useHorizontalStyles,
StepperContent,
} from "./common/stepperContent";
const HorizontalFormStepper = () => {
const classes = useHorizontalStyles();
const { activeStep, handleReset, handleBack, handleNext } = StepperContent();
const steps = getSteps();
return (
<div className={classes.root}>
<Stepper activeStep={activeStep} alternativeLabel>
{steps.map((label) => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
</Step>
))}
</Stepper>
<div>
{activeStep === steps.length ? (
<div>
<Typography className={classes.instructions}>
All steps completed
</Typography>
<Button onClick={handleReset}>Reset</Button>
</div>
) : (
<div>
<Typography className={classes.instructions}>
{getStepContent(activeStep)}
</Typography>
<div>
<Button
disabled={activeStep === 0}
onClick={handleBack}
className={classes.backButton}
>
Back
</Button>
<Button variant="contained" color="primary" onClick={handleNext}>
{activeStep === steps.length - 1 ? "Finish" : "Next"}
{/* {console.log(steps.length - 1)} */}
</Button>
</div>
</div>
)}
</div>
</div>
);
};
export default HorizontalFormStepper;
verticalFormStepper.JSX
import React from "react";
import {
Stepper,
Step,
StepLabel,
StepContent,
Button,
Paper,
Typography,
Grid,
Container,
} from "@material-ui/core/";
import {
getStepContent,
getSteps,
useVerticalStyles,
StepperContent,
} from "./common/stepperContent";
const VerticalFormStepper = () => {
const classes = useVerticalStyles();
const steps = getSteps();
const { activeStep, handleBack, handleNext, handleReset } = StepperContent();
return (
<Container fixed maxWidth="sm">
<Grid>
<Paper variant="outlined" elevation={2}>
<div className={classes.root}>
<Stepper activeStep={activeStep} orientation="vertical">
{steps.map((label, index) => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
<StepContent>
<Typography>{getStepContent(index)}</Typography>
<div className={classes.actionsContainer}>
<div>
<Button
disabled={activeStep === 0}
onClick={handleBack}
className={classes.button}
>
Back
</Button>
<Button
variant="contained"
color="primary"
onClick={handleNext}
className={classes.button}
>
{activeStep === steps.length - 1 ? "Finish" : "Next"}
</Button>
</div>
</div>
</StepContent>
</Step>
))}
</Stepper>
{activeStep === steps.length && (
<Paper square elevation={0} className={classes.resetContainer}>
<Typography>
All steps completed - you're finished
</Typography>
<Button onClick={handleReset} className={classes.button}>
Reset
</Button>
</Paper>
)}
</div>
</Paper>
</Grid>
</Container>
);
};
export default VerticalFormStepper;
【问题讨论】:
-
看起来你可以把这个放在codesandbox上,你能做到吗?
-
谢谢!所以我们要在这里解决的问题是,我们不想在切换到
horizontal和verticalstepper 时丢失用户的进度——反之亦然。 -
问题是你在两个组件中都调用
StepperContent,而不是那样,在父组件中只调用一次并将结果值作为道具传递给组件,这是一个工作版本codesandbox.io/s/fancy-dream-5x4ko -
换句话说,通过在每个组件中调用
StepperContent,您将创建两个状态,每个组件都有自己的状态,而不是共享相同的状态。
标签: javascript reactjs material-ui react-hooks