Skip to content

Commit b1238ad

Browse files
committed
fix: 彻底修复Markdown编辑器数据恢复问题,改用ref直接控制编辑器内容
1 parent 199677d commit b1238ad

File tree

1 file changed

+101
-50
lines changed

1 file changed

+101
-50
lines changed

src/components/ChallengeContributePage/components/DescriptionFields.tsx

Lines changed: 101 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -78,40 +78,115 @@ const markdownEditorStyles = `
7878
}
7979
`;
8080

81+
// 安全地将任何类型的值转换为字符串
82+
const safeToString = (value: any): string => {
83+
if (value === null || value === undefined) {
84+
return '';
85+
}
86+
if (typeof value === 'string') {
87+
return value;
88+
}
89+
if (typeof value === 'object') {
90+
try {
91+
// 尝试从对象中提取text属性或转换为JSON字符串
92+
if (value.text && typeof value.text === 'string') {
93+
return value.text;
94+
}
95+
if (value.toString && value.toString() !== '[object Object]') {
96+
return value.toString();
97+
}
98+
return JSON.stringify(value);
99+
} catch (e) {
100+
console.error('无法将对象转换为字符串', e);
101+
return '';
102+
}
103+
}
104+
return String(value);
105+
};
106+
81107
/**
82108
* 描述字段组件
83109
*/
84110
const DescriptionFields: React.FC<SectionProps> = ({ form }) => {
85-
const [chineseMarkdown, setChineseMarkdown] = useState<string>('');
86-
const [englishMarkdown, setEnglishMarkdown] = useState<string>('');
111+
// 状态
87112
const [markdownRenderer, setMarkdownRenderer] = useState<any>({
88113
render: (text: string) => text
89114
});
115+
116+
// refs
90117
const styleRef = useRef<HTMLStyleElement | null>(null);
91-
const isInitializedRef = useRef<boolean>(false);
118+
const editorChineseRef = useRef<MdEditor | null>(null);
119+
const editorEnglishRef = useRef<MdEditor | null>(null);
120+
const hasInitializedRef = useRef<boolean>(false);
92121

93-
// 安全地将表单值转换为字符串
94-
const ensureString = (value: any): string => {
95-
if (value === null || value === undefined) {
96-
return '';
97-
}
98-
if (typeof value === 'string') {
99-
return value;
100-
}
101-
if (typeof value === 'object') {
122+
// 当本地存储里的值变化时,重新初始化编辑器内容
123+
useEffect(() => {
124+
// 监听存储变化
125+
const handleStorageChange = () => {
126+
try {
127+
// 等待一个周期让React首先更新Form
128+
setTimeout(() => {
129+
// 从表单直接获取最新状态
130+
const chineseValue = form.getFieldValue('descriptionMarkdown');
131+
const englishValue = form.getFieldValue('descriptionMarkdownEn');
132+
133+
// 安全转换为字符串
134+
const chineseText = safeToString(chineseValue);
135+
const englishText = safeToString(englishValue);
136+
137+
// 直接更新编辑器内容
138+
if (editorChineseRef.current?.getMdElement) {
139+
editorChineseRef.current.setText(chineseText);
140+
}
141+
142+
if (editorEnglishRef.current?.getMdElement) {
143+
editorEnglishRef.current.setText(englishText);
144+
}
145+
}, 0);
146+
} catch (err) {
147+
console.error('处理存储变化时出错:', err);
148+
}
149+
};
150+
151+
window.addEventListener('storage', handleStorageChange);
152+
return () => {
153+
window.removeEventListener('storage', handleStorageChange);
154+
};
155+
}, [form]);
156+
157+
// 初始化编辑器内容
158+
useEffect(() => {
159+
if (hasInitializedRef.current) return;
160+
161+
// 等待编辑器加载完成
162+
setTimeout(() => {
102163
try {
103-
// 尝试从对象中提取text属性或转换为JSON字符串
104-
if (value.text && typeof value.text === 'string') {
105-
return value.text;
164+
// 获取表单中的字段值
165+
const chineseValue = form.getFieldValue('descriptionMarkdown');
166+
const englishValue = form.getFieldValue('descriptionMarkdownEn');
167+
168+
// 安全转换为字符串
169+
const chineseText = safeToString(chineseValue);
170+
const englishText = safeToString(englishValue);
171+
172+
// 更新编辑器内容
173+
if (editorChineseRef.current?.getMdElement) {
174+
editorChineseRef.current.setText(chineseText);
175+
// 确保表单中也保存了正确的字符串
176+
form.setFieldsValue({ descriptionMarkdown: chineseText });
106177
}
107-
return JSON.stringify(value);
108-
} catch (e) {
109-
console.error('无法将对象转换为字符串', e);
110-
return '';
178+
179+
if (editorEnglishRef.current?.getMdElement) {
180+
editorEnglishRef.current.setText(englishText);
181+
form.setFieldsValue({ descriptionMarkdownEn: englishText });
182+
}
183+
184+
hasInitializedRef.current = true;
185+
} catch (err) {
186+
console.error('设置初始编辑器内容时出错:', err);
111187
}
112-
}
113-
return String(value);
114-
};
188+
}, 300); // 延迟更久以确保编辑器已完全初始化
189+
}, [form]);
115190

116191
// 处理图片上传
117192
const handleImageUpload = (file: File): Promise<string> => {
@@ -130,13 +205,12 @@ const DescriptionFields: React.FC<SectionProps> = ({ form }) => {
130205

131206
// 处理中文描述变化
132207
const handleChineseEditorChange = ({ text }: { text: string }) => {
133-
setChineseMarkdown(text);
208+
// 确保更新的是字符串值
134209
form.setFieldsValue({ descriptionMarkdown: text });
135210
};
136211

137212
// 处理英文描述变化
138213
const handleEnglishEditorChange = ({ text }: { text: string }) => {
139-
setEnglishMarkdown(text);
140214
form.setFieldsValue({ descriptionMarkdownEn: text });
141215
};
142216

@@ -194,30 +268,7 @@ const DescriptionFields: React.FC<SectionProps> = ({ form }) => {
194268
}
195269
`;
196270

197-
// 同步初始值到state
198-
useEffect(() => {
199-
if (isInitializedRef.current) return;
200-
201-
// 获取表单中的值并确保是字符串类型
202-
const chnDesc = ensureString(form.getFieldValue('descriptionMarkdown'));
203-
const engDesc = ensureString(form.getFieldValue('descriptionMarkdownEn'));
204-
205-
// 设置到state中
206-
setChineseMarkdown(chnDesc);
207-
setEnglishMarkdown(engDesc);
208-
209-
// 如果恢复的值不是字符串类型,纠正表单中的值
210-
if (typeof form.getFieldValue('descriptionMarkdown') !== 'string') {
211-
form.setFieldsValue({ descriptionMarkdown: chnDesc });
212-
}
213-
214-
if (typeof form.getFieldValue('descriptionMarkdownEn') !== 'string') {
215-
form.setFieldsValue({ descriptionMarkdownEn: engDesc });
216-
}
217-
218-
isInitializedRef.current = true;
219-
}, [form]);
220-
271+
// 初始化markdown-it和样式
221272
useEffect(() => {
222273
// 动态加载markdown-it库
223274
const script = document.createElement('script');
@@ -260,10 +311,10 @@ const DescriptionFields: React.FC<SectionProps> = ({ form }) => {
260311
rules={[{ required: true, message: '请输入中文描述' }]}
261312
>
262313
<MdEditor
314+
ref={editorChineseRef}
263315
style={{ height: '300px' }}
264316
renderHTML={text => markdownRenderer.render(text)}
265317
onChange={handleChineseEditorChange}
266-
value={chineseMarkdown}
267318
placeholder="请使用Markdown格式输入题目描述,支持图片、代码块等。可以直接粘贴图片!"
268319
config={editorConfig}
269320
onImageUpload={handleImageUpload}
@@ -275,10 +326,10 @@ const DescriptionFields: React.FC<SectionProps> = ({ form }) => {
275326
label="英文描述 (Markdown)"
276327
>
277328
<MdEditor
329+
ref={editorEnglishRef}
278330
style={{ height: '300px' }}
279331
renderHTML={text => markdownRenderer.render(text)}
280332
onChange={handleEnglishEditorChange}
281-
value={englishMarkdown}
282333
placeholder="请使用Markdown格式输入英文题目描述(可选),英文版将在用户切换语言时显示。可以直接粘贴图片!"
283334
config={editorConfig}
284335
onImageUpload={handleImageUpload}

0 commit comments

Comments
 (0)