Reputation: 1021
I am making a simple accordion which has text editor inside it.
If we click expand text then the text editor gets opened and if we enter some text inside the editor and click shrink, then the accordion gets closed.
Again if click on the expand text of accordion where we made the changes, then the text already entered is missing inside it.
I can understand that this re render every time we click on the expand text. Also this code,
<Text> {toggleValue === index && item.content && <EditorContainer />} </Text>
check for the item clicked then it gets opened so re render happens here and hence I am losing the entered text.
Complete working example:
Could you please kindly help me to retain the value entered inside the text editor despite of the clicks over the text Expand/Shrink?
Upvotes: 0
Views: 1198
Reputation: 371193
Put the editor's state into a persistent parent component. Since the NormalAccordion
encompasses all editors, and you want persistent state just one editor, use another component, so that the state doesn't get lost when the editor unmounts, then pass it down for the editor to use:
const OuterEditorContainer = ({ toggleValue, setToggleValue, item, index }) => {
const [editorState, setEditorState] = useState(EditorState.createEmpty());
const toggleHandler = (index) => {
index === toggleValue ? setToggleValue(-1) : setToggleValue(index);
};
return (
<Accordion>
<Heading>
<div
style={{ padding: "10px", cursor: "pointer" }}
className="heading"
onClick={() => toggleHandler(index)}
>
{toggleValue !== index ? `Expand` : `Shrink`}
</div>
</Heading>
<Text>
{toggleValue === index && item.content && (
<EditorContainer {...{ editorState, setEditorState }} />
)}
</Text>
</Accordion>
);
};
const NormalAccordion = () => {
const [toggleValue, setToggleValue] = useState(-1);
return (
<div className="wrapper">
{accordionData.map((item, index) => (
<OuterEditorContainer
{...{ toggleValue, setToggleValue, item, index }}
/>
))}
</div>
);
};
// text_editor.js
export default ({ editorState, setEditorState }) => (
<div className="editor">
<Editor
editorState={editorState}
onEditorStateChange={setEditorState}
toolbar={{
inline: { inDropdown: true },
list: { inDropdown: true },
textAlign: { inDropdown: true },
link: { inDropdown: true },
history: { inDropdown: true }
}}
/>
</div>
);
You could also put the state into the text_editor
itself, and always render that container, but only conditionally render the <Editor
.
Upvotes: 1
Reputation: 342
You need to save the entered text and pass it as props from the parent component to EditorContainer.
Right now everytime you render it (e.g. when we click expand) It looks like you set an empty state.
Something like:
EditorContainer
editorState: this.props.editorState || EditorState.createEmpty()
onEditorStateChange = (editorState) => {
// console.log(editorState)
this.props.setEditorState(editorState);
};
And in Accordion:
{toggleValue === index &&
item.content &&
<EditorContainer
editorState={this.state.editorState[index]}
setEditorState={newText => this.setState({...this.state, newText}) />}
Didn't try to execute it, but I think that's the way to achieve it. Ps: Class components are almost not used anymore. Try to use function components and learn about useState hook, looks so much cleaner in my opinion
Upvotes: 1