调用API时React Quill的defaultValue无法正常显示
React Quill 无法用API数据预填充内容的解决方案
问题根源
- React Quill 属性错误:你给React Quill传了自定义的
state属性,但React Quill本身是用value实现受控模式的,state属性完全无效,导致数据更新时编辑器无法同步。 defaultValue仅初始化生效:defaultValue只会在组件第一次渲染时赋值,而API数据是异步返回的,等数据回来时组件已经挂载完成,defaultValue不会触发编辑器更新。useEffect执行顺序问题:你先调用getIsp再设置urlId,第一次执行getIsp时urlId是空字符串,可能导致查询参数错误(虽你说能拿到数据,但逻辑上存在隐患)。
修复步骤
1. 修正 EditorComponent,使用官方受控属性
把自定义的state参数换成value,这是React Quill官方支持的受控属性:
import React from 'react'; import ReactQuill from 'react-quill'; const modules = { toolbar: [ [{ font: [] }], [{ header: [1, 2, 3, 4, 5, 6, false] }], ['bold', 'italic', 'underline', 'strike'], [{ color: [] }, { background: [] }], [{ script: 'sub' }, { script: 'super' }], ['blockquote', 'code-block'], [{ list: 'ordered' }, { list: 'bullet' }], [{ indent: '-1' }, { indent: '+1' }, { align: [] }], ['link', 'image', 'video'], ['clean'] ] }; const EditorComponent = ({ placeholder, value, onChange, defaultValue }) => { return ( <ReactQuill defaultValue={defaultValue} value={value} modules={modules} theme='snow' placeholder={placeholder} onChange={onChange} /> ); }; export default EditorComponent;
2. 调整 UpdateISPEntry 组件的状态管理与 useEffect 逻辑
- 在API请求完成时直接同步编辑器状态;
- 修复
useEffect执行顺序,先设置urlId再调用查询; - 用受控模式(
value={notesState})让编辑器和状态同步:
const UpdateISPEntry = () => { const [formValues, setFormValues] = useState(); const [urlId, setUrlId] = useState(''); const [previousState, setPreviousState] = useState(); const [notesState, setNotesState] = useState(); // 编辑器受控状态 const [getIsp, { data, loading, error }] = useLazyQuery(GET_ISP_ENTRY, { variables: { ispListEntryId: urlId }, onCompleted: () => { const notesData = data?.ispListEntry?.notes; setNotesState(notesData); // 直接同步到编辑器状态 setFormValues(data?.ispListEntry); }, onError: () => { toast.error(error); } }); console.log(loading ? 'Loading...' : data?.ispListEntry?.notes); const [ submitValues, { data: successful, loading: successLoading, error: loadingError } ] = useMutation(UPDATE_ISP_ENTRY, { onError: () => { toast.error(`There was an error ${loadingError}`); } }); const params = useLocation(); const path = params.pathname; const pathSplit = path.split('/')[2]; useEffect(() => { // 先设置urlId,再调用查询 setUrlId(pathSplit); if (pathSplit) { // 确保pathSplit有效再发起查询 getIsp(); } }, [pathSplit, getIsp]); // 移除不必要的依赖,避免无限循环 const handleSubmit = () => {}; return ( <Fragment> <div className='container p-4 parent-container'> <ISPFormHeader /> <ISPFormHeaderPagename children='Update ISP Entry' /> <ISPForm initialValues={data?.ispListEntry} enableReinitialize={true} onSubmit={handleSubmit} /> <div className='editor-fields'> <EditorComponent value={notesState} // 用受控属性value绑定状态 onChange={setNotesState} placeholder='Enter Notes Here' /> </div> <div className='editor-fields'> <EditorComponent placeholder='Enter Previous Notes Here' value={previousState} onChange={setPreviousState} /> </div> </div> </Fragment> ); }; export default UpdateISPEntry;
额外说明
如果你不想用受控模式,也可以给EditorComponent加一个key,当API数据更新时改变key,强制组件重新渲染,让defaultValue重新生效:
<EditorComponent key={data?.ispListEntry?.notes ? 'notes-loaded' : 'notes-empty'} defaultValue={data?.ispListEntry?.notes} onChange={setNotesState} />
但受控模式是React Quill推荐的用法,稳定性更高。
内容的提问来源于stack exchange,提问作者timbo245
相关产品推荐
相关产品推荐

