#javascript #reactjs #editor #accordion
#javascript #reactjs #редактор #аккордеон
Вопрос:
Я создаю простой аккордеон, внутри которого есть текстовый редактор.
Если мы нажмем развернуть текст, откроется текстовый редактор, а если мы введем некоторый текст внутри редактора и нажмем сжать, то аккордеон закроется.
Опять же, если щелкнуть по развернутому тексту accordion, где мы внесли изменения, то уже введенный текст в нем отсутствует.
Я могу понять, что это повторный рендеринг каждый раз, когда мы нажимаем на развернутый текст. Также этот код,
<Text> {toggleValue === index amp;amp; item.content amp;amp; <EditorContainer />} </Text>
проверьте, нажат ли элемент, затем он открывается, поэтому здесь происходит повторный рендеринг, и, следовательно, я теряю введенный текст.
Полный рабочий пример:
Не могли бы вы любезно помочь мне сохранить значение, введенное в текстовом редакторе, несмотря на щелчки по тексту Expand / Shrink?
Ответ №1:
Поместите состояние редактора в постоянный родительский компонент. Поскольку NormalAccordion
включает в себя все редакторы, и вам нужно постоянное состояние только одного редактора, используйте другой компонент, чтобы состояние не терялось при отключении редактора, затем передайте его редактору для использования:
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 amp;amp; item.content amp;amp; (
<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>
);
Вы также можете поместить состояние в text_editor
само по себе и всегда отображать этот контейнер, но только условно отображать <Editor
.
Комментарии:
1. Спасибо за ваш ответ.. Не могли бы вы, пожалуйста, предоставить рабочую изолированную среду, разветвив мою в вопросе?
2. Изменения в ответе — это действительно все, что вам нужно, но если вам тоже нужна ссылка: codesandbox.io/s/react-accordion-forked-mi7s0?file=/src /…
3. Еще раз спасибо за предоставление ссылки.. Но здесь, если я ввожу текст внутри любого редактора, и если я закрываю этот аккордеон, и если я открываю любой другой аккордеон, то ранее введенный текст присутствует внутри другого аккордеона, который не имеет значения.. Не могли бы вы, пожалуйста, проверить это?
4. Введенный текст внутри редактора связан только с этим конкретным аккордеоном.. Теперь изменение в любом текстовом редакторе отражается во всех других текстовых редакторах..
5. О, у вас есть
.map
, так что у них у всех было бы одинаковое состояние. Используйте разные контейнеры для каждого редактора и вместо этого помещайте в них постоянное состояние для каждого.
Ответ №2:
Вам нужно сохранить введенный текст и передать его в качестве реквизита из родительского компонента в EditorContainer.
Прямо сейчас каждый раз, когда вы его визуализируете (например, когда мы нажимаем развернуть) Похоже, вы установили пустое состояние.
Что-то вроде:
EditorContainer
editorState: this.props.editorState || EditorState.createEmpty()
onEditorStateChange = (editorState) => {
// console.log(editorState)
this.props.setEditorState(editorState);
};
И в аккордеоне:
{toggleValue === index amp;amp;
item.content amp;amp;
<EditorContainer
editorState={this.state.editorState[index]}
setEditorState={newText => this.setState({...this.state, newText}) />}
Не пытался выполнить это, но я думаю, что это способ добиться этого.
PS: Компоненты класса почти больше не используются. Попробуйте использовать функциональные компоненты и узнайте о крючке useState, на мой взгляд, выглядит намного чище