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.
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? :