Skip to content

docs: In React -> Reveal.destroy on unmount does not fully destroy #3645

@GiffE

Description

@GiffE

The docs suggestion on how to use Reveal with react seem to have a bug.

From: https://revealjs.com/react/

    const deckRef = useRef<Reveal.Api | null>(null); // reference to deck reveal instance

    useEffect(() => {
        // Prevents double initialization in strict mode
        if (deckRef.current) return;

        deckRef.current = new Reveal(deckDivRef.current!, {
            transition: "slide",
            // other config options
        });

        deckRef.current.initialize().then(() => {
            // good place for event handlers and plugin setups
        });

        return () => {
            try {
                if (deckRef.current) {
                    deckRef.current.destroy();
                    deckRef.current = null;
                }
            } catch (e) {
                console.warn("Reveal.js destroy call failed.");
            }
        };
    }, []);

This expressly violates the pitfall described in the React documentation:
https://react.dev/learn/synchronizing-with-effects#dont-use-refs-to-prevent-effects-from-firing

This causes reveal to not unmount properly, the observable bug is that the keyboard bindings from a previous instance remain.

React docs suggest that a cancelation be used instead:
https://react.dev/learn/synchronizing-with-effects#fetching-data

Writing in an abort variable seems to fix the issue along with setting the ref only after initialization.

    useEffect(() => {
        let abortInitialize = false;
        let deck = new Reveal(deckDivRef.current!, {
            transition: "slide",
            // other config options
        });

        deck.initialize().then(() => {
    
            if (abortInitialize) {
                deck.destroy();
                return;
            }

            // good place for event handlers and plugin setups

            deckRef.current = deck;
        });

        return () => {
            try {
                abortInitialize = true;
                if (deckRef?.current?.isReady()) {
                    deckRef.current.destroy();
                    deckRef.current = null;
                }
            } catch (e) {
                console.warn('Reveal.js destroy call failed.');
            }
        };
    }, []);

Related issue:
#3593

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions