I've a simple use case: There's a DraftEditor ponent which takes value
as its prop and create a editor state based on value
(empty or with content). It possible that the value
gets changed by the parent and when it does, I expect the Draft Editor to update it's content as well. Here's my DraftEditor
ponent.
import React, { useState } from "react";
import { Editor, EditorState, convertFromRaw } from "draft-js";
export default ({ value }) => {
const initialState = value
? EditorState.createWithContent(convertFromRaw(JSON.parse(value)))
: EditorState.createEmpty();
const [editorState, setEditorState] = useState(initialState);
return <Editor editorState={editorState} onChange={setEditorState} />;
};
The problem: When value
is updated by the parent ponent, the contents of Editor
is not getting updated. Instead, it just shows the content it was initialized with. The workaround I found is to manually call setEditorState
when the value
changes, but I feel this step is unnecessary as when the ponent re-renders I expect the editor to recalculate it's internal state as well? May be I am missing something here?
Any idea why the Editor
is not updating it's internal state?
Here's a code sandbox: ;hidenavigation=1&theme=dark
I've a simple use case: There's a DraftEditor ponent which takes value
as its prop and create a editor state based on value
(empty or with content). It possible that the value
gets changed by the parent and when it does, I expect the Draft Editor to update it's content as well. Here's my DraftEditor
ponent.
import React, { useState } from "react";
import { Editor, EditorState, convertFromRaw } from "draft-js";
export default ({ value }) => {
const initialState = value
? EditorState.createWithContent(convertFromRaw(JSON.parse(value)))
: EditorState.createEmpty();
const [editorState, setEditorState] = useState(initialState);
return <Editor editorState={editorState} onChange={setEditorState} />;
};
The problem: When value
is updated by the parent ponent, the contents of Editor
is not getting updated. Instead, it just shows the content it was initialized with. The workaround I found is to manually call setEditorState
when the value
changes, but I feel this step is unnecessary as when the ponent re-renders I expect the editor to recalculate it's internal state as well? May be I am missing something here?
Any idea why the Editor
is not updating it's internal state?
Here's a code sandbox: https://codesandbox.io/s/xenodochial-sanderson-i95vd?fontsize=14&hidenavigation=1&theme=dark
Share Improve this question asked Jan 20, 2020 at 23:18 VeeraVeera 33.2k36 gold badges100 silver badges138 bronze badges1 Answer
Reset to default 8The basic problem is
const [editorState, setEditorState] = useState(initialState);
uses it's parameter initialState
only once (on initial run-through), no matter how many times initialState
changes.
When using useState()
and there is a prop (or other) dependency, pair it with a useEffect()
to make things reactive.
This may seem a bit backwards, but a lot of (most of) the hooks are about keeping things the same when the Function ponent is re-run. So useState()
only updates editorState
via setEditorState
, after the initial call.
import React, { useState, useEffect } from "react";
import { Editor, EditorState, convertFromRaw } from "draft-js";
export default ({ value }) => {
const [editorState, setEditorState] = useState();
useEffect(() => {
const state = value
? EditorState.createWithContent(convertFromRaw(JSON.parse(value)))
: EditorState.createEmpty();
setEditorState(state);
}, [value]); // add 'value' to the dependency list to recalculate state when value changes.
return <Editor editorState={editorState} onChange={setEditorState} />;
};
In the code above, editorState will be null on initial ponent call. If this is a problem for the Editor
ponent, you can externalize the state calculation in a function and call it for useState()
and within useEffect()
.
import React, { useState, useEffect } from "react";
import { Editor, EditorState, convertFromRaw } from "draft-js";
export default ({ value }) => {
const [editorState, setEditorState] = useState(calcState(value));
useEffect(() => {
setEditorState(calcState(value));
}, [value]); // add 'value' to the dependency list to recalculate state when value changes.
return <Editor editorState={editorState} onChange={setEditorState} />;
};
const calcState = (value) => {
return value
? EditorState.createWithContent(convertFromRaw(JSON.parse(value)))
: EditorState.createEmpty();
}
Since those two hooks are used together a lot, I tend to pair them in a custom hook to encapsulate the detail.
The difference is that the custom hook runs every time the Component runs, but editorState
still only updates when value changes.
Custom hook
import React, { useState, useEffect } from "react";
import { EditorState, convertFromRaw } from "draft-js";
export const useConvertEditorState = (value) => {
const [editorState, setEditorState] = useState(calcState(value));
useEffect(() => {
setEditorState(calcState(value));
}, [value]);
return [editorState, setEditorState];
}
const calcState = (value) => {
return value
? EditorState.createWithContent(convertFromRaw(JSON.parse(value)))
: EditorState.createEmpty();
}
Component
import React, { useState, useEffect } from "react";
import { Editor } from "draft-js";
import { useConvertEditorState } from './useConvertEditorState'
export default ({ value }) => {
const [editorState, setEditorState] = useConvertEditorState(value);
return <Editor editorState={editorState} onChange={setEditorState} />;
};
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744200893a4562872.html
评论列表(0条)