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
useCallbackRead frequently changing values? :