Hank
Hank

Reputation: 2616

How to recreate draggable/scrollable mui tabs in typescript

I have this javascript draggable tabs component, it is a copy from another question here: mui-tablist with react beautiful dnd not auto scrolling on drag and it has a codesandbox

My aim is to migrate to typescript and eventually create something similar to the following mockup.

enter image description here

Migrating to typescript: I have taken the above question/answer and merged them together as best I can

import React from 'react';
import TabContext from "@mui/lab/TabContext";
import TabPanel from "@mui/lab/TabPanel";
import { DragDropContext, Droppable, DropResult } from "react-beautiful-dnd";
import { Draggable } from "react-beautiful-dnd";
import { Stack, styled, Tab, Tabs } from "@mui/material";

interface DraggableTabProps {
  label: string;
  value: string;
  index: number;
  key: number;
  child: JSX.Element;
};

const DraggableTab = ( props: DraggableTabProps ) => {
  return (
    <Draggable
      draggableId={`${props.index}`}
      index={props.index}
      disableInteractiveElementBlocking
    >
      {(draggableProvided) => (
        <div
          ref={draggableProvided.innerRef}
          {...draggableProvided.draggableProps}
        >
          {React.cloneElement(props.child, {
            ...props,
            ...draggableProvided.dragHandleProps
          })}
        </div>
      )}
    </Draggable>
  );
}

const StyledTabs = styled(Tabs)();
const StyledTab = styled(Tab)();

export default function DraggableTabComponent() {
  const [value, setValue] = React.useState('1');
  
  const handleChange = (event: React.SyntheticEvent, newValue: string) => {
    setValue(newValue);
  };

  const [tabs, setTabs] = React.useState(
    [...Array(25)].map((_, index) => ({
      id: `tab${index + 1}`,
      label: `Tab ${index + 1}`,
      value: `${index + 1}`,
      content: `Content ${index + 1}`
    }))
  );

  const onDragEnd = (result: DropResult) => {
    const newTabs = Array.from(tabs);
    const draggedTab = newTabs.splice(result.source.index, 1)[0];
    newTabs.splice(result.destination!.index, 0, draggedTab);
    setTabs(newTabs);
  };

  return (
    <TabContext value={value}>
      <Stack>
        <DragDropContext onDragEnd={onDragEnd}>
          <Droppable droppableId="1" direction="horizontal">
            {(droppableProvided) => (

              <StyledTabs
                ref={droppableProvided.innerRef}
                {...droppableProvided.droppableProps}
                value={value}
                onChange={handleChange}
                variant="scrollable"
                scrollButtons
                allowScrollButtonsMobile
              >
                {tabs.map((tab, index) => {
                  const child = (
                    <StyledTab label={tab.label} value={tab.value} key={index} />
                  );

                  return (
                    <DraggableTab
                      label={tab.label}
                      value={tab.value}
                      index={index}
                      key={index}
                      child={child}
                    />
                  );
                })}
                {droppableProvided ? droppableProvided.placeholder : null}
              </StyledTabs>
            )}
          </Droppable>
        </DragDropContext>
      </Stack>
      {tabs.map((tab, index) => (
        <TabPanel value={tab.value} key={index}>
          {tab.content}
        </TabPanel>
      ))}
    </TabContext>
  );
}

This displays the tabs and I am able to click each tab and view its content, but I get an error along with each click for the draggable, e.g. on the first tab:

react_devtools_backend.js:4026 react-beautiful-dnd Unable to find draggable with id: 0

Could use some help to fix this up, thanks

Upvotes: 0

Views: 930

Answers (1)

Arislan Makhmudov
Arislan Makhmudov

Reputation: 197

It's a known issue with react-beautiful-dnd package, and it occurs only in dev mode and React v18.

Strict mode checks are run in development mode only; they do not impact the production build.

Apparently, to solve it you have to disable strict mode for the part of your application that uses your Tab component which is not the best solution, or just ignore the issue because it is not present in the production mode.

Upvotes: 1

Related Questions