英文:
my blog writing input is removing last line in react
问题
这是当前状态,我有4行代码和第5行在当前输入中。
这是我的React代码,我正在尝试让它像Medium一样工作,您可以单独编辑每一行。
英文:
this is the current state where I have 4 lines and 5th line in current input
and this is my react code
import { FC, useEffect, useState } from "react";
interface BlogWitterProps {}
const BlogWitter: FC<BlogWitterProps> = ({}) => {
const [markdownContent, setMarkdownContent] = useState("");
const [currentLine, setCurrentLine] = useState("");
// on each new line, update the markdown content
useEffect(() => {
console.log("markdownContent", markdownContent);
console.log("currentLine", currentLine);
}, [currentLine, markdownContent]);
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
setMarkdownContent((prev) => {
return prev + currentLine + "\n";
});
setCurrentLine("");
} else if (e.key === "Backspace" && currentLine === "") {
e.preventDefault();
setMarkdownContent((prev) => {
const lines = prev.split("\n");
const lastLine = lines.pop();
console.log("lines", lines);
setTimeout(() => {
// If the last line is not empty, update the current line state
if (lastLine !== "") {
setCurrentLine(lastLine + "\n");
} else {
setCurrentLine("");
}
}, 0);
return lines.join("\n");
});
}
};
return (
<div className="">
<div>
{markdownContent.split("\n").map((line, index) => {
return (
<div key={index}>
{line}
<br />
</div>
);
})}
</div>
<input
value={currentLine}
onChange={(e) => {
setCurrentLine(e.target.value);
}}
className="w-full resize-none outline-none text-2xl bg-transparent border border-black"
onKeyDown={handleKeyDown}
/>
</div>
);
};
export default BlogWitter;
so if I press backspace and it takes me to last line to edit then press anter again without changing anything it is remove the last line's new line and gives me this
I am trying to get it to work as in medieum where you can edit each line seperatly
答案1
得分: 1
以下是您要翻译的内容:
"事件序列在字符代码打印到控制台的情况下更容易理解markdownContent
。
下面,我重新粘贴了代码,并添加了一些测试代码(第16-21行),以将markdownContent
显示为一系列由管道(|)字符分隔的ASCII字符代码。
关键序列和markdownContent字符代码
步骤 | 关键序列 | 输入字段 | 字符代码 |
---|---|---|---|
1 | A + Enter | A | 65 | 10 |
2 | B + Enter | B | 65 | 10 | 66 | 10 |
3 | C + Enter | C | 65 | 10 | 66 | 10 | 67 | 10 |
4 | 退格 | 65 | 10 | 66 | 10 | 67 | |
5 | 退格 | C | 65 | 10 | 66 |
6 | 输入 | 65 | 10 | 66 | 67 | 10 | 10 |
通过代码步进
在步骤4中,按下退格键执行第33行。这会将步骤3中的字符代码拆分为chr(10)(换行符)。第34行弹出最后一个字符(换行符),第42行将其丢弃,因为输入文本字段为空(调用了setCurrentLine("")
)。
在步骤5中,再次按下退格键(因为在步骤4之后输入字段未移动)。再次执行第33行,将步骤4中的字符拆分为换行符,弹出第34行的chr(67)(字母C),丢弃C。在按下退格键之前,输入表单字段为空,导致调用setCurrentLine("")
。C被从markdownContent
中丢弃,但被重新添加到输入文本字段中。
在步骤6中,按下Enter键会导致问题的描述。在这里,步骤5中的字符与currentLine
连接:(C)+ Enter(刚刚按下的Enter键)。这就是字母BC被连接在一起的地方。原始的换行符将这两个字符分开,被第33行中的split()
调用在步骤5中消耗。第27行添加了第二个换行符。这就是我们在步骤6中看到两个换行符的原因。
注意事项
在文本输入正确运行之前,需要考虑几种情况和边界情况。
代码
import * as React from "react";
const { useEffect, useState } = React;
interface BlogWitterProps {}
const BlogWitter: React.FunctionComponent<BlogWitterProps> = ({}) => {
const [markdownContent, setMarkdownContent] = useState("");
const [currentLine, setCurrentLine] = useState("");
// 在每一行结束时,更新markdown内容
useEffect(() => {
console.log("markdownContent", markdownContent);
console.log("currentLine", currentLine);
let chars = [];
for (let c of markdownContent) {
chars.push(c.charCodeAt(0));
}
let codeString = chars.join('|');
console.log('codes: ' + codeString);
}, [currentLine, markdownContent]);
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
setMarkdownContent((prev) => {
return prev + currentLine + "\n";
});
setCurrentLine("");
} else if (e.key === "Backspace" && currentLine === "") {
e.preventDefault();
setMarkdownContent((prev) => {
const lines = prev.split("\n");
const lastLine = lines.pop();
console.log("lines", lines);
setTimeout(() => {
// 如果最后一行不为空,更新当前行状态
if (lastLine !== "") {
setCurrentLine(lastLine + "\n");
} else {
setCurrentLine("");
}
}, 0);
return lines.join("\n");
});
}
};
return (
<div className="">
<div>
{markdownContent.split("\n").map((line, index) => {
return (
<div key={index}>{ line }</div>
);
})}
</div>
<input
value={currentLine}
size={80}
onChange={(e) => {
setCurrentLine(e.target.value);
}}
className="w-full resize-none outline-none text-2xl bg-transparent border border-black"
onKeyDown={handleKeyDown}
/>
</div>
);
};
export default BlogWitter;
"
英文:
The sequence of events is easier to understand when the character codes for markdownContent
are printed to the console.
Below, I've re-pasted the code, with some test code in place (LINES 16-21) to display markdownContent
as a series of ASCII character codes separated by the pipe (|) character.
Key sequences and markdownContent char codes
step | key sequence | input field | char codes |
---|---|---|---|
1 | A + Enter | A | 65 | 10 |
2 | B + Enter | B | 65 | 10 | 66 | 10 |
3 | C + Enter | C | 65 | 10 | 66 | 10 | 67 | 10 |
4 | Backspace | 65 | 10 | 66 | 10 | 67 | |
5 | Backspace | C | 65 | 10 | 66 |
6 | Enter | 65 | 10 | 66 | 67 | 10 | 10 |
Stepping through the code
At step 4, pressing Backspace executes LINE 33. This splits the character codes in step 3 by chr(10) (linefeed). LINE 34 pops the last character (linefeed), and LINE 42 discards it since the input text field is blank (setCurrentLine("")
is called).
At step 5 Backspace is pressed again (because the input field did not move after step 4). LINE 33 is executed again, splitting the characters in step 4 by linefeed, popping chr(67) (letter C) at LINE 34, and discarding C. The input form field is blank just prior to pressing Backspace, causing setCurrentLine("")
to be called. C is discarded from markdownContent
but is re-added to the input text field.
At step 6 Enter is pressed causing the problem described in the question. Here, the characters in step 5 are joined with currentLine
: (C) + Enter (the Enter key just pressed). This is where the letters BC are joined together. The original linefeed that would have separated these two characters is consumed by the call to split()
at step 5 in LINE 33. LINE 27 adds a second linefeed. This is why we see two linefeeds at step 6.
Notes
There are several cases and edge cases that need to be considered before text input will behave correctly.
Code
1. import * as React from "react";
2.
3. const { useEffect, useState } = React;
4.
5. interface BlogWitterProps {}
6.
7. const BlogWitter: React.FunctionComponent<BlogWitterProps> = ({}) => {
8. const [markdownContent, setMarkdownContent] = useState("");
9. const [currentLine, setCurrentLine] = useState("");
10.
11. // on each new line, update the markdown content
12.
13. useEffect(() => {
14. console.log("markdownContent", markdownContent);
15. console.log("currentLine", currentLine);
16. let chars = [];
17. for ( let c of markdownContent ) {
18. chars.push( c.charCodeAt( 0 ) );
19. }
20. let codeString = chars.join('|');
21. console.log( 'codes: ' + codeString );
22. }, [currentLine, markdownContent]);
23.
24. const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
25. if (e.key === "Enter") {
26. setMarkdownContent((prev) => {
27. return prev + currentLine + "\n";
28. });
29. setCurrentLine("");
30. } else if (e.key === "Backspace" && currentLine === "") {
31. e.preventDefault();
32. setMarkdownContent((prev) => {
33. const lines = prev.split("\n");
34. const lastLine = lines.pop();
35. console.log("lines", lines);
36.
37. setTimeout(() => {
38. // If the last line is not empty, update the current line state
39. if (lastLine !== "") {
40. setCurrentLine(lastLine + "\n");
41. } else {
42. setCurrentLine("");
43. }
44. }, 0);
45.
46. return lines.join("\n");
47. });
48. }
49. };
50.
51. return (
52. <div className="">
53. <div>
54. {markdownContent.split("\n").map((line, index) => {
55. return (
56. <div key={index}>{ line }</div>
57. );
58. })}
59. </div>
60. <input
61. value={currentLine}
62. size={ 80 }
63. onChange={(e) => {
64. setCurrentLine(e.target.value);
65. }}
66. className="w-full resize-none outline-none text-2xl bg-transparent border border-black"
67. onKeyDown={handleKeyDown}
68. />
69. </div>
70. );
71. };
72.
73. export default BlogWitter;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论