React: handling updating settings without breaking component?

I’m building a Wordpress Gutenberg plugin that uses the Lightgallery javascript plugin.

I have an object called lgSettings that defines all of the LightGallery settings (of which there are a few dozen), and a control for each of those settings.

The lgSettings object gets saved inside the attributes objects for use on the backend for rendering.

I have my component built as follows, and it works fine on intial page load, but when I change one of the settings, it will no longer open. It’s as if it’s trying to open, because the image will enlarge a bit and start moving to the center of the window, but then it disappears. I can’t quite suss out what is changing in terms of the html elements or their CSS that’s making it do that…

import React, { useState, useEffect, useRef, useCallback } from 'react';
import LightGallery from 'lightgallery/react';
import lgZoom from 'lightgallery/plugins/zoom';
import lgHash from 'lightgallery/plugins/hash';
import 'lightgallery/css/lightgallery.css';

const LcpGallery = (props) => {
  const [settings, setSettings] = useState({
    elementClassNames: 'lcp-gallery grid',
    plugins: [],
    zoom: false,
    hash: false,
    download: false
  });

  const lightGallery = useRef(null);

  // onInit callback to initialize the lightGallery instance
  const onInit = useCallback((detail) => {
    if (detail) {
      lightGallery.current = detail.instance;
    }
  }, []);

  // Update settings based on the props
  useEffect(() => {
    console.log("Props received:", props);

    const plugins = [];

    // Convert plugin strings to actual plugin functions
    if (props.plugins) {
      props.plugins.forEach((plugin) => {
        console.log(`Adding plugin: ${plugin}`);
        if (plugin === 'lgZoom') {
          plugins.push(lgZoom); // Add lgZoom function
        } else if (plugin === 'lgHash') {
          plugins.push(lgHash); // Add lgHash function
        }
      });
    }

    // Update settings with new plugins and options
    setSettings((prevSettings) => ({
      ...prevSettings,
      plugins,         // Updated plugins
      zoom: props.zoom || false, // Default zoom option
      hash: props.hash || false, // Default hash option
      download: props.download || false
    }));
  }, [props]);

  // Reinitialize gallery when settings change (with careful timing)
  useEffect(() => {
    console.log("Settings changed:", settings);

    // Check if gallery instance exists and only refresh if initialized
    if (lightGallery.current) {
      console.log("Refreshing gallery...");
      lightGallery.current.refresh();  // Refresh the gallery instance
    }
  }, [settings]);

  return (
    <LightGallery
      ref={lightGallery}
      plugins={settings.plugins}
      elementClassNames={settings.elementClassNames}
      zoom={settings.zoom}
      hash={settings.hash}
      download={settings.download}
      onInit={onInit}  // Pass the onInit callback to initialize the gallery instance
    >
      {/* Gallery Items */}
      <a
        data-lg-size="1600-1067"
        className="gallery-item"
        data-src="https://images.unsplash.com/photo-1609342122563-a43ac8917a3a?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1600&q=80"
        data-sub-html="<h4>Photo by - <a href='https://unsplash.com/@tobbes_rd' >Tobias Rademacher </a></h4><p> Location - <a href='https://unsplash.com/s/photos/puezgruppe%2C-wolkenstein-in-gr%C3%B6den%2C-s%C3%BCdtirol%2C-italien'>Puezgruppe, Wolkenstein in Gröden, Südtirol, Italien</a>layers of blue.</p>"
      >
        <img
          alt="layers of blue."
          className="img-responsive"
          src="https://images.unsplash.com/photo-1609342122563-a43ac8917a3a?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=240&q=80"
        />
      </a>

      <a
        data-lg-size="1600-2400"
        className="gallery-item"
        data-src="https://images.unsplash.com/photo-1608481337062-4093bf3ed404?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1600&q=80"
        data-sub-html="<h4>Photo by - <a href='https://unsplash.com/@therawhunter' >Massimiliano Morosinotto </a></h4><p> Location - <a href='https://unsplash.com/s/photos/tre-cime-di-lavaredo%2C-italia'>Tre Cime di Lavaredo, Italia</a>This is the Way</p>"
      >
        <img
          className="img-responsive"
          src="https://images.unsplash.com/photo-1608481337062-4093bf3ed404?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=240&q=80"
        />
      </a>
    </LightGallery>
  );
};

export default LcpGallery;
{/* The Gallery */}
<LcpGallery {...attributes.lgSettings} />

And an example of a control to change the settings is

{/* Zoom Settings - Zoom requires lgZoom plugin */}
                    <ToggleControl
                      label={__('Enable Zoom', 'lcp')}
                      checked={lgSettings.zoom}
                      onChange={(value) => {
                        // Update autoplay
                        setAttributes({
                          lgSettings: {
                            ...lgSettings,
                            zoom: value, // Update the zoom setting
                            plugins: value
                              ? [...lgSettings.plugins, 'lgZoom'] // Add lgFullScreen plugin if enabled
                              : lgSettings.plugins.filter(plugin => plugin !== 'lgZoom'), // Remove lgFullScreen plugin if disabled
                          },
                        });
                      }}
                    />

Essentially what I am trying to do is pass the attributes.lgSettings object to the component, since that object contains all of the necessary settings, and then refresh the component when with the new settings when a setting changes.

Hi @jeremy58 , I tried your code and updating the settings doesn’t seem to break anything per se… not sure what exactly the expected behaviour is apart from that though. Here’s a stackblitz:

Maybe you can incorporate your toggle component here to “make it break”? The issue might be somewhere else I guess.

1 Like

I think you’re right…

This is being built as a Wordpress Gutenberg block. There’s something wild going on, because the gallery seems to be being initialized “at random.”

I see the console message of “Product key XXXX isn’t valid…” about 10 times after the page loads, and I believe that only happens when a gallery is initialized…