How to fix this error about state in react?
P粉214176639
P粉214176639 2024-04-01 09:32:43
0
1
452

I want to make a simple react app where when I press enter on a block, a new block will appear under that block and the rest behind it will be under the new block.

But when there are multiple blocks, when I press enter on the previous block, the latter block disappears.

I do not understand. Can anyone point out this error?

The following are some codes and pictures:

editablePage.tsx

import { useState } from "react";
import EditableBlock, { BlockType } from "../editableBlock";

export default function EditablePage() {
  const [blocks, setBlocks] = useState<BlockType[]>([
    { tag: "h1", content: "Welcome", position: 0 },
  ]);

  function addBlockHandler({ tag, position }: BlockType) {
    const nextPosition = position + 1;
    const newBlock: BlockType = {
      tag: tag,
      content: nextPosition.toString(),
      position: nextPosition,
    };
    console.log(blocks);
    const blocksBeforeNew = blocks.slice(0, nextPosition);
    const blocksAfterNew = blocks.slice(nextPosition).map((block) => {
      const copy = { ...block };
      copy.position += 1;
      return copy;
    });
    const updatedBlocks = blocksBeforeNew
      .concat(newBlock)
      .concat(blocksAfterNew);
    setBlocks(updatedBlocks);
  }

  return (
    <div>
      {blocks.map(({ tag, content, position }: BlockType) => {
        return (
          <EditableBlock
            key={position}
            tag={tag}
            position={position}
            content={content}
            addBlock={addBlockHandler}
          />
        );
      })}
    </div>
  );
}

editableBlock.tsx

import { useState } from "react";
import ContentEditable, { ContentEditableEvent } from "react-contenteditable";

type TagType = "h1" | "h2" | "h3" | "p";

export interface BlockType {
  tag: TagType;
  content: string;
  position: number;
}

export interface EditableBlockProps extends BlockType {
  addBlock: (currentBlock: BlockType) => void;
}

export default function EditableBlock({
  tag,
  content,
  position,
  addBlock,
}: EditableBlockProps) {
  const [text, setText] = useState<string>(content);

  const handleChange = (evt: ContentEditableEvent) => {
    setText(evt.target.value);
  };

  const handleKeyDown = (evt: React.KeyboardEvent<HTMLElement>) => {
    if (evt.key === "Enter") {
      evt.preventDefault();
      addBlock({ tag, content, position });
    }
  };

  return (
    <ContentEditable
      tagName={tag}
      html={text}
      onChange={handleChange}
      onKeyDown={handleKeyDown}
    />
  );
}

Before:

After pressing Enter on the first block:

I found out that the error comes from blocks but I don't understand why this happens.

P粉214176639
P粉214176639

reply all(1)
P粉557957970

This is a known issue with react-contenteditable, please see lovasoa/react-contenteditable# 161:

Of the workarounds proposed in the linked question, you can try this comment which is useEventCallback shown in how-to-read-an- every-change-value-from-usecallback" rel="nofollow noreferrer">Legacy React Documentation > How to read from useCallback Read frequently changing values? :

const useRefCallback = (
  value: ((...args: T) => void) | undefined,
  deps?: React.DependencyList
): ((...args: T) => void) => {
  const ref = React.useRef(value);

  React.useEffect(() => {
    ref.current = value;
  }, deps ?? [value]);

  const result = React.useCallback((...args: T) => {
    ref.current?.(...args);
  }, []);

  return result;
};

// Usage
export function EditablePage() {
  // State, addBlockHandler function...

  const addBlock2 = useRefCallback(addBlockHandler);

  return (
    
{blocks.map(({ tag, content, position }: BlockType) => { return ( ); })}
); }
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template