#javascript #reactjs #material-ui #react-hooks
#javascript #reactjs #материал-пользовательский интерфейс #реагирующие перехваты
Вопрос:
Я пытаюсь синхронизировать 2 компонента с состоянием их родительского компонента, используя перехваты React. Я использую горизонтальный и вертикальный шаговые устройства как 2 отдельных компонента из пользовательского интерфейса material, а их родительский класс содержит содержимое шагового устройства и состояние, в котором они оба должны совместно использоваться. Причина, по которой я использую горизонтальный и вертикальный шаговый переход, заключается в том, чтобы сделать пользовательский интерфейс максимально адаптивным.
Проблема, с которой я сталкиваюсь, заключается в том, что, когда activeStep
увеличивается на один из компонентов, т. Е. на горизонтальный шаговый, насколько я понимаю, жизненный цикл монтирования компонента. вызывается метод визуализации, и Activestep увеличивается и отражается в dom. но это отражается только в горизонтальном шаговом механизме. изменение распространяется только в горизонтальном шаговом компоненте. при навигации по компоненту вертикального шагового перехода он возвращает начальное состояние перехвата, которое изначально было установлено в 0.
Я пытаюсь синхронизировать горизонтальный и вертикальный шаговые операции с activeStep
в stepperContent, и любое изменение состояния должно распространяться в обоих компонентах.
Мой вопрос
Как мне синхронизировать их с функциональным компонентом с отслеживанием состояния activeState
в stepperContent?
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 amp;amp; (
<Paper square elevation={0} className={classes.resetContainer}>
<Typography>
All steps completed - youamp;apos;re finished
</Typography>
<Button onClick={handleReset} className={classes.button}>
Reset
</Button>
</Paper>
)}
</div>
</Paper>
</Grid>
</Container>
);
};
export default VerticalFormStepper;
Комментарии:
1. Похоже, вы можете поместить это в codesandbox, вы можете это сделать?
2. codesandbox.io/s/young-feather-70×21?file=/src/App.js
3. Спасибо! Итак, проблема, которую мы хотим исправить здесь, заключается в том, что мы не хотим терять прогресс пользователя при переключении на
horizontal
иvertical
stepper — или наоборот.4. Проблема в том, что вы вызываете
StepperContent
в обоих компонентах, вместо этого вызывайте его только один раз в родительском компоненте и передавайте значение результата в качестве реквизита компоненту, вот рабочая версия codesandbox.io/s/fancy-dream-5x4ko5. Другими словами, вызывая
StepperContent
в каждом компоненте, вы создаете два состояния, каждый компонент имеет свое собственное состояние вместо того, чтобы они разделяли одно и то же состояние.
Ответ №1:
Другим возможным решением является использование 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();
...
Может быть излишним, но это есть.