Open sneakers-the-rat opened 3 years ago
since the progress bar is now also rendered for every slide, once you have appreciable slides you end up rendering an n^2 number of elements if you include it -- eg for a slideshow of 40 slides that's 1600 additional elements in the DOM. I haven't profiled but my slideshows are significantly laggier when I have any variant of a progress bar object (the base progress bar included)
it would be nice to be able to render an object that can access the DeckContext once rather than needing to include something on every slide. when I try and use DeckContext at the level of the deck though it has reference errors from unmounted slides. this seems like a pretty common use case (eg. progress bars, contact info, content overlays that persist between slides) that would make me elevate this issue from a feature request to a bug since the performance hit seems to be so massive
This works except for that now all the intra-slide steps are broken, that must be computed when the deck is initially mounted?
rendering them on first mount of Deck (by adding a || !initialized
check) seems to fix the number of steps, and all my custom stepper components work, but now Appear components are broken because they seem to be tied to a specific stepID rather than a step #
edit: confirmed that providing an explicit 'id' to Appear fully fixes and everything is way way way way faster
First off: you're absolutely right about Progress
, and I'm kind of annoyed at myself for not catching it. 😅
Secondly: your suggestion absolutely holds water. The problems you're running into most likely have to do with the fact that Slides need to actually render their contents in order to detect "step participants". Moreover, as you've noticed: slides aren't exactly aware of their location in the presentation- they only know that the Deck addresses them by their slide ID. So the solution is more or less to have the Deck keep track of which slides should be rendered and which slides shouldn't, and signal them accordingly.
You could technically implement a fix with some creative usage of DeckContext
and your HideSlide
component, but it's much easier to implement in-core. So I'm cutting that PR now.
Here is a simple way to only mount a slide's content if it is active.
First create a wrapper around Slide
like this:
import { useContext, useId } from "react";
import { DeckContext, Slide as SpectacleSlide } from "spectacle";
export const Slide = (props: React.ComponentProps<typeof SpectacleSlide>) => {
const randomId = useId();
const id = props.id ?? randomId;
const { activeView } = useContext(DeckContext);
return (
<SpectacleSlide id={id}>
{id === activeView.slideId && props.children}
</SpectacleSlide>
);
};
and then use it in your deck like this:
import { Deck, Heading, DefaultTemplate } from "spectacle";
import { Slide } from "./shared";
export const App = () => {
return (
<Deck template={<DefaultTemplate />}>
<Slide>
<Heading>My Slide</Heading>
<MyComponent />
</Slide>
{/* and so on...*/}
</Deck>
);
};
Suggestion: this logic could be added to the Slide
component based on isActive
flag in https://github.com/FormidableLabs/spectacle/blob/main/packages/spectacle/src/components/slide/slide.tsx#L438 and then add it as optional props to Slide <Slide unmountInactive=true />
or <Deck unmountInactive=true />
Description
Currently all slides remain in the DOM with display:none when not displayed & the components remain mounted. this means any slides that have components with side effects like animations will continue running, and everything starts going very sloooow.
Proposal
Add a prop to
Deck
likebufferRange
where the content of slides slides +/- that range are mounted in the Dom, but otherwise are unmounted.