johnwalley / allotment

A React component for resizable split views

Home Page:https://allotment.mulberryhousesoftware.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Example usage with Next.js

optimistiks opened this issue · comments

commented

The suggested approach (to use next/dynamic) did not work for me. I could not use Allotment.Pane after dynamically importing with ssr:false, neither from allotment directly nor from an intermediate component file.

But I got it to work using combination of plain import and useEffect just fine.

https://codesandbox.io/s/nextjs-typescript-allotment-c7yvk?file=/components/Panes.tsx

Hi @optimistiks. Thanks for the feedback 🙏.

I'll take a look, make sure I understand what's going on, then add this to the documentation.

To add, the suggested approach using next/dynamic in the other issue is incorrect. As per this comment from a Next maintainer, next/dynamic is only used to import components.

The library is now being successfully used in several NextJS projects. I will check what the status is.

Any updates on this? I'm trying with NextJS 13 but I don't get the blue bars rendered on hover. It looks like its SSRing and showing the smallest possible container size.

The library is now being successfully used in several NextJS projects. I will check what the status is.

Would you be so kind to link a working example? I am not able to make the Panes work, nor register a ref successfully with Next12 and React 18.

the ref.current returns and object with the retry function only

Based on the linked code sandbox, I created this hook, it works but has an issue.
It produces a warning

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

If you have a fix for it, please post it (probably forwardRef or convert default state to class-based components), if you don't care feel free to use it. 😄

import { ComponentType, Ref, useEffect, useRef, useState } from "react";

import { AllotmentHandle, AllotmentProps, PaneProps } from "allotment/dist/types/src/allotment";

function useAllotment() {
  const isMountedRef = useRef(false);
  const allotmentRef = useRef<AllotmentHandle>({
    resize: (sizes = [0, 0]) => {
      console.warn("Allotment is not mounted yet", sizes);
    },
    reset: () => {},
  });

  const [Allotment, setAllotment] = useState<
    ComponentType<AllotmentProps & { ref?: Ref<AllotmentHandle> }> & {
      Pane: ComponentType<PaneProps>;
    }
  >(
    () => {
      function Allotment({ children }: AllotmentProps) {
        return <>{children}</>;
      }

      Allotment.Pane = function ({ children }: PaneProps) {
        return <>{children}</>;
      };

      return Allotment;
    },
  );

  useEffect(() => {
    isMountedRef.current = true;
    import("allotment")
      .then(mod => {
        if (!isMountedRef.current) {
          return;
        }

        setAllotment(mod.Allotment);
      })
      .catch(err => console.error(err, `could not import allotment ${err.message}`));

    return () => {
      isMountedRef.current = false;
    };
  }, []);

  return { allotmentRef, Allotment };
}

export default useAllotment;

I can confirm I got allotment working with my Next.JS v13 app

I did need to use the dynamic export

Here is what I did...

@/app/components/allotment.component.tsx

export default function AllotmentCmp() {
  return (
    <Allotment>
         <div></div>
         <div></div>
    </Allotment>
  )
}

@/app/components/app.tsx

export const AllotmentCmp = dynamic(
  () => import('@/app/components/allotment.component'),
  { ssr: false }
)

function App(){
   return (
      <AllotmentCmp/>
   )
}