-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Stepper] Document how to avoid re-mounting between each step #22534
Comments
@alehechka What makes you believe that the issue is on the Material-UI side? What's happening if you replace material-table with the work in progress data grid? Please provide a minimal reproduction test case. This would help a lot 👷 . |
@alehechka I'm working on something that also requires the stepper to stop unmounting the when it is inactive. Can you please tell me what you changed and where you changed it for your solution to work? I'm not familiar with TS but I can try. |
@doodhJalebi Thanks for the question, now I think I understand what problem @alehechka was facing. What about we update the documentation to include: https://material-ui.com/components/accordion/#performance. I believe the problem is the same. We can leverage the same solution: add the same section in the documentation. |
@oliviertassinari that would be just perfect! Quick question: would this update to the docs be a patch or will I have to wait till v5 comes out? |
@doodhJalebi This has been supported since v1. The documentation would be on v5 (next branch). Do you want to give it a try? :) |
@oliviertassinari I would love to give it a try (only if its not too much of a hassle for you). |
@oliviertassinari Thanks for updating this to be a doc related issue, I think that's definitely the route to go since I don't think this is the fault of material-ui. I was originally following the Stepper docs here. In the example code it uses the function getStepContent that will return the text to be used on that step. I changed that up a bit to instead supply the actual material-table component to be rendered. But due to the intensity of re-mounting the material-table so often is what caused the slow down. My solution provided above was to instead keep all components mounted but hidden when its step is not active. |
@doodhJalebi Go ahead, it will save us time. Note that the tradeoff of the Stepper is opposite to the Accordion. We don't mount all the steps to speed up the initial mount. |
@oliviertassinari sorry for going AWOL. Um, noob questions but uh when you say "go ahead" or "give it a try", where do I go exactly? I apologize for my confusion 😕 |
@doodhJalebi I was referring to opening a pull request. However, looking back at the problem, it doesn't seem to be a frequent request. I'm closing. An answer on GitHub' issue is already something developers can search and find (if they spend enough time) |
Is it right that material-ui library re-mounts every step inside the stepper when switching back and forward between the steps? If so, how could I prevent this functionality? Currently I am experiencing issues with the stat being reset to default on switching back and forward. Also with an instance of formik and formik persists after going back and forward twice, the formik persist state is also reset to defaults. Looking forward for your answer. Thanks! |
@kevinvugts Are you using the vertical stepper? I think that the behavior is correct. You will find #10569 for developers advocating for the current behavior. I'm reopening as, after all, we might benefit from documentation about it. The following should be enough: diff --git a/docs/src/pages/components/steppers/steppers.md b/docs/src/pages/components/steppers/steppers.md
index 34004243f6..25a8c6c373 100644
--- a/docs/src/pages/components/steppers/steppers.md
+++ b/docs/src/pages/components/steppers/steppers.md
@@ -70,6 +70,16 @@ Vertical steppers are designed for narrow screen sizes. They are ideal for mobil
{{"demo": "pages/components/steppers/VerticalLinearStepper.js"}}
+### Performance
+
+The content of a step is unmounted when closed.
+If you need to make the content available to search engines or render expensive component trees inside your modal while optimizing for interaction responsiveness
+it might be a good idea to keep the step mounted with:
+
+```jsx
+<StepContent TransitionProps={{ unmountOnExit: false }} />
+```
+
## Mobile stepper
This component implements a compact stepper suitable for a mobile device. It has more limited functionality than the vertical stepper. See [mobile steps](https://material.io/archive/guidelines/components/steppers.html#steppers-types-of-steps) for its inspiration. What do you think about it? Do you want to open a pull request? |
Thanks for your prompt reply! I am using the Horizontal Stepper at the moment. Does this component also has access to the TransitionProps? |
@kevinvugts The horizontal stepper doesn't have this notion, so I think that you are looking at the wrong place. |
What would be the solution for the Horizontal Stepper? Is there a way I could prevent the unmounting components? |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
I'll take this, if no one is working on it. |
Did you get any solution? I've been trying with vertical and horizontal stepper and |
Have you got any solution? |
CustomStepper ComponentOverviewThe Features
Static Array Issue and SolutionProblem: When the steps in the stepper are static (i.e., not changing dynamically), the component may re-render more often than necessary, which can affect performance. Solution: To optimize performance, use a static array for steps instead of dynamically generating it. This approach prevents unnecessary re-renders and improves efficiency. Implementation Steps
Full Component Codeimport React, { useCallback, useMemo, useState } from "react";
import { styled } from "@mui/material/styles";
import Stack from "@mui/material/Stack";
import Stepper from "@mui/material/Stepper";
import Step from "@mui/material/Step";
import StepLabel from "@mui/material/StepLabel";
import Check from "@mui/icons-material/Check";
import StepConnector, { stepConnectorClasses } from "@mui/material/StepConnector";
import DropdownModal from "../DropdownModal/DropdownModal";
import Tooltip from "@mui/material/Tooltip";
// Styles for connectors and step icons
// (Styles as provided above)
// Component definition
const CustomStepper = React.memo(function CustomStepper({
steps,
activeStep,
connectorType = "qonto",
icons,
highlightStep,
label_status,
HandleAddRating,
stepColors,
}) {
const Connector = useMemo(
() => (connectorType === "colorlib" ? ColorlibConnector : QontoConnector),
[connectorType]
);
const StepIconComponent = useMemo(
() => (connectorType === "colorlib" ? ColorlibStepIcon : QontoStepIcon),
[connectorType]
);
const [modalOpen, setModalOpen] = useState(false);
const [selectedIcon, setSelectedIcon] = useState("D");
const handleStepClick = useCallback(
(icon, index) => {
setSelectedIcon(icon);
if (stepColors[index] !== "#4caf50") {
setModalOpen(true);
}
},
[stepColors]
);
const handleClose = useCallback(() => setModalOpen(false), []);
const allStepsCompleted = useMemo(
() => activeStep >= steps.length,
[activeStep, steps.length]
);
const handleSaveRating = useCallback(
(ratingObject) => {
HandleAddRating(ratingObject);
setModalOpen(false);
},
[HandleAddRating]
);
const stepsMore = ["D", "O", "E", "R", "-R"];
return (
<>
{connectorType === "colorlib" ? (
<ColorlibGlobalStyles />
) : (
<GlobalStyles />
)}
<Stack sx={{ width: "100%" }} spacing={4}>
<Stepper
alternativeLabel
activeStep={activeStep}
connector={<Connector stepColor={stepColors[activeStep]} />}
>
{stepsMore.map((label, index) => (
<Step key={label}>
<Tooltip title={steps[index]} arrow>
<span>
<StepLabel
StepIconComponent={(props) => (
<StepIconComponent
{...props}
icon={icons ? icons[index + 1] : undefined}
onClick={() =>
handleStepClick(icons[index + 1], index)
}
highlight={highlightStep === index}
stepColor={stepColors[index]}
allCompleted={allStepsCompleted}
/>
)}
>
<span>{label}</span>
</StepLabel>
</span>
</Tooltip>
</Step>
))}
</Stepper>
</Stack>
<DropdownModal
open={modalOpen}
handleClose={handleClose}
selectedIcon={selectedIcon}
HandleAddRating={handleSaveRating}
step_name={steps[activeStep]}
label_status={label_status}
/>
</>
);
}, (prevProps, nextProps) => {
return (
prevProps.activeStep === nextProps.activeStep &&
prevProps.connectorType === nextProps.connectorType &&
prevProps.highlightStep === nextProps.highlightStep &&
prevProps.label_status === nextProps.label_status &&
JSON.stringify(prevProps.steps) === JSON.stringify(nextProps.steps) &&
JSON.stringify(prevProps.stepColors) ===
JSON.stringify(nextProps.stepColors)
);
});
export default CustomStepper; |
In my application, I was rendering two different material-tables in two different steps of the Stepper component. When trying to test switching between steps quickly it would begin slowing down considerably and eventually freeze (in which I had to close the browser tab to continue).
I'm not sure the process for contributing code so I'm attaching below how I went around this by instead setting
display: none;
on all non-active steps.Here's an example of what the array of StepContentProps looks like:
The text was updated successfully, but these errors were encountered: