admin管理员组

文章数量:1123793

I'm building a dock like layout for react, similar to dockview. I have a recursive dock structure working, and I'm trying to get the resizing handles to work for different docks. It somewhat works, however when I resize a dock, if it has any children that are also docks then those children's sizes will be reset to their initial value.

To replicate this behavior with the below code, drag the slider between the Left of Top Right and Right of Top Right panels, then drag the vertical slider directly to the left of the Left of Top Right panel. Notice how the slider between Left of Top Right and Right of Top Right returned to its original position.

import React, { useState, useEffect, useRef } from 'react';

const locationsCSS = {
  full: "",
  left: "self-start",
  right: "self-end",
  top: "self-start",
  bottom: "self-end",
}

const directionCSS = {
  horizontal: "flex-row",
  vertical: "flex-col",
}

const baseCSS = "p-4"

const Dock = ({ location, children, width, height }) => {
  const direction = children.length > 0
    ? ["left", "right"].includes(children[0]?.location) ? "horizontal" : "vertical"
    : "";

  const [firstDockSize, setFirstDockSize] = useState(() =>
    direction === "horizontal" ? width / 2 : height / 2
  );

  const isResizing = useRef(false);
  const startPos = useRef(0);
  const initialSize = useRef(0);

  const handleMouseDown = (e) => {
    isResizing.current = true;
    startPos.current = direction === "horizontal" ? e.clientX : e.clientY;
    initialSize.current = firstDockSize;

    document.addEventListener("mousemove", handleMouseMove);
    document.addEventListener("mouseup", handleMouseUp);
  };

  const handleMouseMove = (e) => {
    if (!isResizing.current) return;

    const delta = direction === "horizontal"
      ? e.clientX - startPos.current
      : e.clientY - startPos.current;

    setFirstDockSize(
      Math.max(
        50,
        Math.min(
          initialSize.current + delta,
          direction === "horizontal" ? width - 50 : height - 50
        )
      )
    );
  };

  const handleMouseUp = () => {
    isResizing.current = false;
    document.removeEventListener("mousemove", handleMouseMove);
    document.removeEventListener("mouseup", handleMouseUp);
  };

  useEffect(() => {
    setFirstDockSize(direction === "horizontal" ? width / 2 : height / 2);
  }, [width, height, direction]);

  return (
    <div
      className={`flex ${direction === "horizontal" ? "flex-row" : "flex-col"}`}
      style={{
        width: `${width}px`,
        height: `${height}px`,
        overflow: "hidden",
      }}
    >
      {Array.isArray(children) ? (
        <>
          {/* First Dock */}
          <div
            style={{
              flexBasis: `${firstDockSize}px`,
              flexGrow: 0,
              flexShrink: 0,
              overflow: "hidden",
            }}
          >
            <Dock
              location={children[0].location}
              children={children[0].children}
              width={direction === "horizontal" ? firstDockSize : width}
              height={direction === "horizontal" ? height : firstDockSize}
            />
          </div>

          {/* Divider */}
          <div
            style={{
              cursor: direction === "horizontal" ? "col-resize" : "row-resize",
              backgroundColor: "#ccc",
              width: direction === "horizontal" ? "3px" : "100%",
              height: direction === "horizontal" ? "100%" : "3px",
            }}
            onMouseDown={handleMouseDown}
          ></div>

          {/* Second Dock */}
          <div
            style={{
              flexGrow: 1,
              overflow: "hidden",
            }}
          >
            <Dock
              location={children[1].location}
              children={children[1].children}
              width={direction === "horizontal" ? width - firstDockSize : width}
              height={direction === "horizontal" ? height : height - firstDockSize}
            />
          </div>
        </>
      ) : (
        <div
          style={{
            overflow: "auto",
          }}
        >
          {children}
          <p>{width}x{height}</p>
        </div>
      )}
    </div>
  );
};

export default function Home() {
  const [testState, setTestState] = useState(0);

  const [windowWidth, setWindowWidth] = useState(0);
  const [windowHeight, setWindowHeight] = useState(0);

  useEffect(() => {
    setWindowWidth(window.innerWidth);
    setWindowHeight(window.innerHeight);

    setInterval(() => {
      setTestState((prev) => prev + 1);
    }, 1000);
  }, []);

  const data = {
    location: "full",
    children: [
      {
        location: "left",
        children: [
          {
            location: "top",
            children: (
              <p>Top Left {testState}</p>
            )
          },
          {
            location: "bottom",
            children: [
              {
                location: "top",
                children: (
                  <p>Top of Bottom Left</p>
                )
              },
              {
                location: "bottom",
                children: (
                  <p>Bottom of Bottom Left</p>
                )
              }
            ]
          }
        ]
      },
      {
        location: "right",
        children: [
          {
            location: "top",
            children: [
              {
                location: "left",
                children: (
                  <p>Left of Top Right</p>
                )
              },
              {
                location: "right",
                children: (
                  <p>Right of Top Right</p>
                )
              }
            ]
          },
          {
            location: "bottom",
            children: (
              <p>Bottom Right</p>
            )
          }
        ]
      }
    ]
  }

  return (
    <div className="w-screen h-screen">
      <Dock location={data.location} children={data.children} width={windowWidth} height={windowHeight}/>
    </div>
  )
}

本文标签: reactjsResizing A Recursive Dock Layout Causing IssuesStack Overflow