Я пытаюсь создать простой Материал пользовательского интерфейса Stepper , чтобы позволить пользователю нажимать Далее и Назад , а также на шаге, но это вызываетдва раза.
Я прочитал где-то , что решение этой проблемы - ловушка useCallback
или useMemo
, которая избегает реализации функции более одного раза и возвращает функцию или результат, только еслиэто меняется.
Моя проблема в том, что все еще ясный пример, я не уверен, как применить это к моему коду. Я собирался использовать простое управление состоянием, которое прекрасно работает. Но я хотел бы узнать это ...
Это моя App
функция:
function App() {
const [completed, setCompleted] = React.useState({});
const [activeStep, dispatchActiveStep] = React.useReducer((step, action) => {
let completedSteps = completed;
let active = step;
switch (action.type) {
case "next":
if (step < steps.length) {
completedSteps[activeStep] = true;
active = step + 1;
}
break;
case "previous":
if (step > 0) {
delete completed[activeStep];
active = step - 1;
}
break;
case "set":
if (!(action.step in Object.keys(completed))) {
console.error("step not completed");
return step;
}
if (action.step === 0) {
completedSteps = {};
active = 0;
} else if (action.step === steps.length - 1) {
completedSteps = {};
for (let i = 0; i <= action.step; i++) {
completedSteps[i] = true;
}
active = action.step;
}
break;
default:
console.error("action not available");
}
console.log("test");
setCompleted(completedSteps);
return active;
}, 0);
return (
<Paper>
<Stepper activeStep={activeStep}>
{steps.map((step, i) => (
<Step key={i}>
<StepButton
key={i}
completed={completed[i]}
onClick={() => dispatchActiveStep({ type: "set", step: i })}
>
<Typography>{step.label}</Typography>
</StepButton>
</Step>
))}
</Stepper>
{steps.map((step, i) => {
if (activeStep === i) {
return (
<div key={i} style={styles.content}>
{step.component}
</div>
);
}
})}
<div style={styles.buttons}>
<Button
color="primary"
variant="contained"
onClick={() => dispatchActiveStep({ type: "previous" })}
disabled={activeStep === 0}
>
Previous
</Button>
<Button
color="secondary"
variant="contained"
style={{ marginLeft: "10px" }}
onClick={() => dispatchActiveStep({ type: "next" })}
disabled={activeStep === steps.length - 1}
>
Next
</Button>
</div>
</Paper>
);
}
У меня естьпопробовал этот код, но он все еще не работает, так как он по-прежнему перерисовывается при вызове dispatchActiveStep()
:
function App() {
const [completed, setCompleted] = React.useState({});
const [activeStep, setActiveStep] = React.useState(0);
const handleBack = () => {
let completedSteps = completed;
if (activeStep === steps.length - 1) {
delete completedSteps[activeStep - 1];
} else {
delete completedSteps[activeStep];
}
setCompleted(completedSteps);
setActiveStep(activeStep - 1);
};
const handleNext = () => {
let completedSteps = completed;
completedSteps[activeStep] = true;
setCompleted(completedSteps);
setActiveStep(activeStep + 1);
};
const handleClick = step => {
let completedSteps = completed;
if (!(step in Object.keys(completedSteps))) {
console.error("step not completed");
return;
}
completedSteps = {};
for (let i = 0; i < step; i++) {
completedSteps[i] = true;
}
setActiveStep(step);
setCompleted(completedSteps);
};
return (
<Paper>
<Stepper activeStep={activeStep}>
{steps.map((step, i) => (
<Step key={i}>
<StepButton
key={i}
completed={completed[i]}
onClick={() => {
handleClick(i);
}}
>
<Typography>{step.label}</Typography>
</StepButton>
</Step>
))}
</Stepper>
{steps.map((step, i) => {
if (activeStep === i) {
return (
<div key={i} style={styles.content}>
{step.component}
</div>
);
}
})}
<div style={styles.buttons}>
<Button
color="primary"
variant="contained"
onClick={handleBack}
disabled={activeStep === 0}
>
Previous
</Button>
<Button
color="secondary"
variant="contained"
style={{ marginLeft: "10px" }}
onClick={handleNext}
disabled={activeStep === steps.length - 1}
>
Next
</Button>
</div>
</Paper>
);
}