Skip to content
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

React: resizestop event does not work with setState as expected #2974

Open
mirinnes opened this issue Mar 2, 2025 · 2 comments
Open

React: resizestop event does not work with setState as expected #2974

mirinnes opened this issue Mar 2, 2025 · 2 comments
Labels

Comments

@mirinnes
Copy link

mirinnes commented Mar 2, 2025

Hi guys, my issue is in relation with resizestop event + setState behaviour in React.

GIven a state called dynamicHeight, when trying to change it through resizestop, its value changes but this change is not reflected in the DOM.

Calling setDynamicHeight from another component (such as a button for example) works perfectly as it should. It is in the moment when I call setDynamicHeight from inside grid.on("resizestop", ... ) event when it stops working and the components do not "react" to the state update

any ideas why this is so?
what can be missing on resizestop event for React to not react on state changes triggered by it?

import { useEffect, useRef } from 'react';

function Demo() {
  const gridContainerRef = useRef<HTMLDivElement>(null)
  const [dynamicHeight, setDynamicHeight] = useState<string>("some height")
 
 useEffect(() => {
    if (gridContainerRef.current) {
      const grid = GridStack.init(
        {
          float: false,
          acceptWidgets: true,
          column: 12,
          minRow: 1,
        },
        gridContainerRef.current
      );

      // Here it is the thing that does not work as expected:
      grid.on("resizestop", function() {
            setDynamicHeight("some new height")
      })
    }
  }, []);


  useEffect(() => {
    console.log('dynamicHeight changed:>>', dynamicHeight) 
// This console log actually gets triggered after resizing 
// and shows the correct updated value "some new height"
// but the components in the DOM don't update with it :( 
  }, [dynamicHeight])


  const items =[{ id: 'item-1-1', x: 0, y: 0, w: 2, h: 2 }, { id: 'item-1-2', x: 2, y: 0, w: 2, h: 2 }]

  return (
    <div className="grid-stack" ref={gridContainerRef}>
      {items.map((item, i) => {
        return (
          <div key={item.id} className="grid-stack-item" gs-id={item.id} gs-w={item.w} gs-h={item.h} gs-x={item.x} gs-y={item.y}>
            <div className="grid-stack-item-content">
              {item.id}          
              <div className="dynamicHeight">Some element with a dynamicHeight</div>
            </div>
          </div>
        )
      })}
    </div>
  )
}
@adumesny
Copy link
Member

adumesny commented Mar 2, 2025

@Aysnine ^^^

@adumesny adumesny added the React label Mar 2, 2025
@Aysnine
Copy link
Contributor

Aysnine commented Mar 3, 2025

@mirinnes Thanks for the issue. there is a lot of misunderstanding about the use of gridstack in your code. This is a simplified demo showing how react + gridstack works.

import { GridStack, GridStackWidget } from "gridstack";
import { useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import "gridstack/dist/gridstack.min.css";

// Global variable to store the gridstack containers
const globalGridstackRenderedContainers: {
  el: HTMLElement;
  initWidgetInfo: GridStackWidget;
}[] = [];
GridStack.renderCB = (el: HTMLElement, initWidgetInfo: GridStackWidget) => {
  globalGridstackRenderedContainers.push({ el, initWidgetInfo });
};

export function Demo() {
  const gridContainerRef = useRef<HTMLDivElement>(null);
  const [dynamicHeight, setDynamicHeight] = useState<string>("some height");

  const [, setTrigger] = useState(0);
  const [items] = useState([
    { id: "item-1-1", x: 0, y: 0, w: 2, h: 2 },
    { id: "item-1-2", x: 2, y: 0, w: 2, h: 2 },
  ]);

  useEffect(() => {
    if (gridContainerRef.current) {
      const grid = GridStack.init(
        {
          float: false,
          acceptWidgets: true,
          column: 12,
          minRow: 1,
          // items here. gridstack will render these 'wrappers'
          children: items,
        },
        gridContainerRef.current
      );

      // This is a hack to force the react to re-render
      // because the gridstack library does not trigger a re-render
      // when the items change
      setTrigger((prev) => prev + 1);

      // Here it is the thing that does not work as expected:
      grid.on("resizestop", function () {
        setDynamicHeight("some new height");
      });
    }
  }, [items]);

  useEffect(() => {
    console.log("dynamicHeight changed:>>", dynamicHeight);
    // This console log actually gets triggered after resizing
    // and shows the correct updated value "some new height"
    // but the components in the DOM don't update with it :(
  }, [dynamicHeight]);

  return (
    <div ref={gridContainerRef}>
      {/* Mount react components in the DOM elements rendered by gridstack */}
      {items.map((item) => {
        // find the container that has the same id as the item
        const target = globalGridstackRenderedContainers.find(
          (container) => container.initWidgetInfo.id === item.id
        );

        if (!target) {
          return null;
        }

        // Only render content. no .grid-stack-item-content
        return createPortal(
          <>
            {item.id}
            <div className="dynamicHeight">
              Some element with a dynamicHeight
            </div>
          </>,
          target.el
        );
      })}
    </div>
  );
}

Sorry, react wrapper is still under development, also based on the principle of this simplified demo, will have better development experience later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants