dockview icon indicating copy to clipboard operation
dockview copied to clipboard

react-portals-cache issue when using ref's

Open ConnorTJolley opened this issue 1 year ago • 8 comments

Describe the bug It seems that if you have a registered component which uses a ref for it's rendering, when switching to a layout that also shares the same panel component, the rendering of that panel seems to completely break, seemingly the react-portals-cache is also empty for this element.

To Reproduce Steps to reproduce the behavior:

I tried to replicate the behaviour without using the same package that I'm experiencing it with (Bryntum Grid due to licensing and account being required to download the package, but:

  • Register your components ensuring 1 is a functional component that uses a instantiates a ref backed class, i.e. BryntumGrid in our case
  • Ensure you have to layouts, both referencing the same panel
  • Load layout 1
  • Observe the panel is populated and working correctly image
  • Load layout 2
  • Observe the panel is now empty and the DOM shows an empty react-portals-cache element image
  • Close the panel
  • Re-add the panel
  • Observe the panel is now rendered correctly and working fine

This issue, I'm unsure whether it's based on the Bryntum library I'm using or whether it's something with how the dockview handles loading components that were loaded in previous layouts and any updating of refs that may be required when rendering in a new DOM location or whether it's just based on my implementation that is causing it, any insight would be greatly appreciated

As when you close and re-add the panel, it works perfectly fine again afterwards

Expected behavior I'd expect that components shared across different layouts (Nested dock view, etc) would continue to render fine without having to close & re-add the panel

Screenshots SC's attached as part of steps to reproduce

Desktop (please complete the following information):

  • Browser: Chrome
  • Version: 131.0.6778.140

Additional context Add any other context about the problem here.

ConnorTJolley avatar Dec 18 '24 14:12 ConnorTJolley

react-portals-cache I assume is something that belongs to the third-party package's logic since it's not something found in dockview.

Happy to investigate but might need a little more info. When you say a component that "uses a ref for it's renderering" I'm not entirely sure what you mean by this in the context of React? Could you provide a small snippet of code to clarify please.

mathuo avatar Dec 20 '24 20:12 mathuo

Sorry, yeah, so for example: https://bryntum.com/products/grid/examples/frameworks/react-vite/basic/dist/ we are using this grid component from Bryntum, we have a component which interacts with our context and uses the BryntumGrid to present the data, so we would have something like:

export const XGrid = (props: { gridRef: any }) => {
   // Other hook stuff and functions

   function buildGrid()
   {
       return (
          <BryntumGrid
            ref={props.gridRef}
            ...
          />
       );
   }

   return buildGrid();

}

Panel component declaration as:

const components = {
       grid: (props: IDockviewPanelProps) => {
             return <XGrid gridRef={gridRef} />
       }
}

With the gridRef being drilled down from the parent component which is using the ref along with another Bryntum component for it's drag and drop functionality (which I tested isn't the cause, as I've tried both defining the ref internally in the component and not interacting with the ref at all)

ConnorTJolley avatar Dec 20 '24 20:12 ConnorTJolley

Also may be worth noting, I am using dockview following this example / setup https://codesandbox.io/p/sandbox/github/mathuo/dockview/tree/gh-pages/templates/dockview/nested/javascript

Each layout I'm referring is it's own Dockview instance, and switching the active 'panel' (dockview) loads it's own panels, essentially the root dock instance is structured like:

  • Root (Dockview instance)
    • Layout 1 (Dockview instance)
      • component_1 (Panel & component)
      • component_2 (Panel & component)
    • Layout 2 (Dockview instance)
      • component_2 (Panel & component)
      • component_5 (Panel & component)

So each nested dockview instance is sharing components that are all defined in the root dockview, the issue of the panel content being empty in my instance would be that component_2 would be declaring the BryntumGrid using the ref as detailed in the code snippet I posted previously, when switching the active panel which shows a different dockview instances panels, that is where the content is breaking, unless you close and re-open the panel

I also tried programmatically closing and re-opening the panel, to no success, it's still empty until you manually remove and re-add it

ConnorTJolley avatar Dec 20 '24 20:12 ConnorTJolley

How are you going about using the components props? Anything fancy here like custom parameters or is your application state parsed into the dockview components using a state management tool (i.e React Context, Redux etc etc)?

const MyGridComponent = (props: IDockviewPanelProps) => {
    return <div>{/** render something */}</div>;
};

const components = { 
    myGridComponent: MyGridComponent,
};

const Test = () => {
    const onReady = (event: DockviewReadyEvent) => {
        //
    };

    return <DockviewReact onReady={onReady} components={components} />;
};

mathuo avatar Dec 20 '24 20:12 mathuo

How are you going about using the components props? Anything fancy here like custom parameters or is your application state parsed into the dockview components using a state management tool (i.e React Context, Redux etc etc)?

const MyGridComponent = (props: IDockviewPanelProps) => {
    return <div>{/** render something */}</div>;
};

const components = { 
    myGridComponent: MyGridComponent,
};

const Test = () => {
    const onReady = (event: DockviewReadyEvent) => {
        //
    };

    return <DockviewReact onReady={onReady} components={components} />;
};

I've made a codesandbox to emulate how we've set it all up and I have commented out code that would just fail without the package: https://codesandbox.io/p/sandbox/zealous-hopper-l6n2k8 hopefully that helps

With switching from Layout 1 to Layout 2 being when the grid panel would be empty unless you deleted it and re-added it manually

ConnorTJolley avatar Dec 20 '24 21:12 ConnorTJolley

Out of curiousity do you still experience the same issue if you set defaultRenderer='always' on each DockviewReact component?

mathuo avatar Dec 22 '24 18:12 mathuo

From what I can remember, yeah, tried individually specifying the component to have always as the renderer and on the DockviewReact itself.

I have also tried unloading all panels in Layout 1's Dockview prior to loading any panels into Layout 2's Dockview, with no success either

Which, as another note which makes it even more confusing, we also have another panel that is using the BryntumGantt component: https://bryntum.com/products/gantt/examples/frameworks/react/javascript/gantt-schedulerpro/build/ which also uses a similar approach to providing a ref for it to use, but oddly this component works fine in both layouts (after unloading the panel in Layout1)

Which is also another reason why I was confused and was thinking it was either that the Dockview was doing something when trying to render the component and not passing through the ref properly or whether the library / component itself is doing something odd

ConnorTJolley avatar Dec 22 '24 19:12 ConnorTJolley

I logged on this morning and verified that it does not change the outcome, I have also recorded the following video to demonstrate exactly what I mean, the main panels are the:

  • Layers & Shape (Bryntum Grid)
  • Gantt View (Bryntum Gantt)

https://github.com/user-attachments/assets/b9665b3f-7ba6-487f-a0b3-799ebb51ad38

As you can see, switching between the nested dock views loads it's own layout of panels, both sharing the same components, the Layers & Shape panel just seems to lose it's content, but the Gantt View is perfectly fine, also shows that closing and re-adding the panel fixes it in the current layout (until you switch the active dockview)

ConnorTJolley avatar Dec 23 '24 09:12 ConnorTJolley