我正在尝试使用React挂钩使2个组件与其父组件状态同步。 我将 horizontal 和 vertical stepper 用作与材料UI分开的2个单独的组件,并且它们的父类具有stepper的内容以及它们都的状态应该分享。 我使用水平和垂直步进器的原因是为了使UI尽可能响应。
我遇到的问题是,根据我对组件安装生命周期的了解,当activeStep
以组件之一(即水平步进器)递增时。调用render方法,Activestep递增并反映在dom中。但是它仅反映在水平步进器中。更改仅在水平步进器组件中传播。在垂直步进器组件中导航时,它将返回最初设置为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;
答案 0 :(得分:2)
另一种可能的解决方案是使用Context
API。
// StepperContent.jsx
...
export const StepperContentContext = createContext();
export const useStepperContent = () => useContext(StepperContentContext);
export const StepperContentProvider = ({ children }) => {
...
const value = { activeStep, handleNext, handleBack, handleReset };
return (
<StepperContentContext.Provider value={value}>
{children}
</StepperContentContext.Provider>
);
};
因此,您现在可以使用StepperContent
钩子来代替使用useStepperContent
。
// HorizontalFormStepper.jsx
...
import {
getStepContent,
getSteps,
useHorizontalStyles,
useStepperContent
} from "./common/StepperContent";
const HorizontalFormStepper = () => {
const classes = useHorizontalStyles();
const {
activeStep,
handleReset,
handleBack,
handleNext
} = useStepperContent();
...
可能会过分杀伤,但确实存在。