ReactSortable render nested component?

71 Views Asked by At

My purpose to implement dragging elements from one list to another, example:

  1. Dragging layout2 element (has 2 nested blocks) into editor.
  2. Dragging paragraph into the one of two layout blocks.

The issue that I faced up is the layout block doesn’t save any element inside itself. When dragging layout block into Editor is everything okey but if dragging paragraph into layout block, as I expected its appear there is but its not.

Please check the link with source code: https://stackblitz.com/edit/stackblitz-starters-dwd2dm?file=src%2FApp.tsx

1

There are 1 best solutions below

2
On

One possible reason for this behavior could be related to how you're updating the state when dropping elements into the layout block. In the Layout6 component, when you're updating the state after dropping elements into the layout block, you're concatenating the new list with the existing content:

setList={(newList) => {
  const updatedState = layoutState.map((item) =>
    item.id === sortable.id ? { ...item, content: [...item.content, ...newList] } : item,
  );
  setLayoutState(updatedState);
}}

Instead of directly concatenating the lists ([...item.content, ...newList]), try setting the content directly to the new list:

setList={(newList) => {
  const updatedState = layoutState.map((item) =>
    item.id === sortable.id ? { ...item, content: newList } : item,
  );
  setLayoutState(updatedState);
}}

By doing this, the content of the layout block will be replaced by the dropped elements rather than appended to the existing content.

I tried replacing L98 - L104 with my code, and I feel it works as it doesn't repeat/misinterprete dragged components into layout.

Appended

Replace Layout2 and Layout6 with the following code to check if it works. I tried replacing them with this code, and now drag to Layout2 and Layout6 work fine.

const Layout2 = () => {
  const { layoutState, setLayoutState } = useContext(MyContext);
  return (
    <div style={{ display: 'flex' }}>
      {layoutState[0]?.child.map((layoutItem, idx) => (
        <ReactSortable
          key={layoutItem.id}
          group={{
            name: 'layout-item',
            pull: true,
            put: ['orthography-list', 'editor-list'],
          }}
          animation={150}
          list={layoutItem.context}
          setList={(newList) => {
            const updatedState = [...layoutState];
            updatedState[0].child[idx].context = newList;
            setLayoutState(updatedState);
          }}
          style={{
            border: '1px solid blue',
            margin: 10,
            minHeight: 50,
            width: layoutItem.width[idx],
          }}
          className="layout-container"
        >
          {layoutItem.context?.map((item, idx) => (
            <div
              key={`${item.id}`}
              data-id={`${item.id}`}
              className="layout-content"
            >
              {item.content}
            </div>
          ))}
        </ReactSortable>
      ))}
    </div>
  );
};

const Layout6 = () => {
  const { layoutState, setLayoutState } = useContext(MyContext);

  return (
    <ReactSortable
      list={layoutState[1].child}
      setList={(newList) => {
        const updatedState = [...layoutState];
        updatedState[1].child = newList;
        setLayoutState(updatedState);
      }}
      group={{
        name: 'layout-6',
        pull: true,
        put: [],
      }}
      animation={150}
      style={{
        border: '1px solid skyblue',
        margin: 10,
        minHeight: 50,
        minWidth: 50,
        display: 'flex',
        flexDirection: 'row',
      }}
      className="layout-block"
    >
      {layoutState[1].child.map((sortable) => (
        <ReactSortable
          key={sortable.id}
          data-id={sortable.id}
          group={{
            name: 'layout-item',
            pull: true,
            put: ['orthography-list', 'editor-list'],
          }}
          animation={150}
          list={sortable.context}
          setList={(newList) => {
            const updatedState = [...layoutState];
            updatedState[1].child = updatedState[1].child.map((item) =>
              item.id === sortable.id ? { ...item, context: newList } : item
            );
            setLayoutState(updatedState);
          }}
          style={{
            border: '1px solid blue',
            margin: 10,
            minHeight: 50,
            minWidth: 50,
          }}
          className="layout-container"
        >
          {sortable.context.map((item, idx) => (
            <div
              key={`${item.id}-${idx}`}
              data-id={`${item.id}-${idx}`}
              className="layout-content"
            >
              {item.content}
            </div>
          ))}
        </ReactSortable>
      ))}
    </ReactSortable>
  );
};