Gerenciar o estado do editor no React
Use um único dono para o documento atual. Escolha estado controlado quando o restante da sua aplicação precisar de cada alteração; escolha um editor não controlado quando você só precisar ler o conteúdo ao salvar. Estes exemplos usam o binding React do npm no modo HTML.
Controlado: mantenha o estado local atualizado
"use client";
import { useState } from "react";
import { RichTextEditor } from "@richscripts/richtexteditor/react";
export default function Composer() {
const [html, setHtml] = useState("<p>Start writing...</p>");
return <RichTextEditor
value={html}
onChange={(next) => {
if (typeof next === "string") setHtml(next);
}}
/>;
}Mantenha o valor emitido pelo editor como o seu valor local de edição. Aplique debounce à persistência pela rede separadamente, em vez de devolver de propósito um valor mais antigo ao editor. Evite substituir o documento inteiro por uma cópia normalizada pelo servidor depois de cada salvamento.
O binding distingue os valores que ele mesmo emite das substituições externas. Isso não torna seguras para a seleção todas as transformações da aplicação. Um handler onChange que reformata o HTML e devolve um conteúdo diferente está pedindo ao editor que substitua o conteúdo enquanto alguém digita.
Não controlado: leia o HTML atual ao salvar
"use client";
import { useRef, useState } from "react";
import { RichTextEditor } from "@richscripts/richtexteditor/react";
import type { RichTextEditorReactHandle } from "@richscripts/richtexteditor/react";
export default function Draft({ initialHtml, onSave }: {
initialHtml: string;
onSave: (html: string) => void;
}) {
const editorRef = useRef<RichTextEditorReactHandle>(null);
const [ready, setReady] = useState(false);
return <>
<RichTextEditor ref={editorRef} defaultValue={initialHtml}
onReady={() => setReady(true)} />
<button type="button" disabled={!ready} onClick={() => {
if (editorRef.current?.getEditor()) {
onSave(editorRef.current.getHTMLCode());
}
}}>Save</button>
</>;
}defaultValue define o conteúdo inicial do documento; não é uma forma de enviar alterações posteriores a um editor já montado. A ref expõe getHTMLCode(). A verificação de prontidão impede que um salvamento prematuro trate um editor ainda não inicializado como um documento vazio.
Este exemplo entrega o HTML ao callback da sua aplicação; ele não implementa persistência, conclusão de uploads nem recuperação de erros ao salvar. Se as imagens estiverem habilitadas, use a sequência de upload e salvamento antes de ler o HTML final. Valide e sanitize o conteúdo enviado no servidor.
Trocar de documento e tratar respostas do servidor com segurança
- Use uma identidade de documento estável. Uma
keybaseada no HTML atual ou em um número aleatório remonta o editor durante a edição. - Uma key intencional com o ID do documento pode iniciar um editor novo para outro documento. Confirme ou salve um rascunho com alterações pendentes antes de trocar; uma remontagem descarta o estado da instância, como a seleção e o histórico de desfazer.
- Se você carrega documentos de forma assíncrona, ignore ou aborte a resposta de um documento que não está mais selecionado.
- Acompanhe uma revisão do documento ao salvar. Uma resposta atrasada deve atualizar o status de salvamento da sua própria revisão, não sobrescrever um rascunho mais novo. Verificações de revisão no servidor são necessárias para detectar um salvamento conflitante de outro usuário.
- Não alterne entre os modos controlado e não controlado no meio da sessão. Escolha o padrão ao abrir o documento.
Montagem e Strict Mode
Use o wrapper React fornecido em vez de criar um segundo editor no mesmo elemento host. Se você escrever seu próprio wrapper, crie o editor depois que o host existir, remova os listeners que ele registrou e destrua a instância que ele criou na limpeza. Ignore inicializações assíncronas que terminem depois da desmontagem.
O React Strict Mode pode executar um ciclo extra de configuração e limpeza em desenvolvimento. Mantenha-o habilitado enquanto verifica o comportamento do ciclo de vida. No Next.js, siga o guia de integração com client components; renderizar conteúdo salvo e montar um editor interativo são questões separadas.
Checklist de solução de problemas
- O cursor pula: verifique keys que mudam, componentes recriados, chamadas repetidas a
setHTMLCode()e valores controlados transformados. - O texto digitado desaparece: verifique valores desatualizados vindos de callbacks atrasados, respostas de salvamento e carregamentos de documento.
- O salvamento perde a última edição: leia a ref do editor no momento do envio, em vez de supor que uma notificação de alteração atrasada já atualizou o estado do React.
- Barras de ferramentas duplicadas: verifique inicialização e limpeza duplicadas, inclusive em mudanças de rota e ao reabrir modais.
- Rascunhos grandes ficam lentos: faça o profiling da serialização do HTML, da renderização da pré-visualização e dos salvamentos pela rede de forma independente.
- A entrada por IME falha: teste a composição em chinês ou japonês sem reescrever o conteúdo durante a composição, e verifique o desfazer depois que o texto for confirmado.
Próximos passos: diagnosticar saltos do cursor passo a passo, instalar o binding React, ou experimentar envio de formulário e salvar e carregar.
Referências: React Strict Mode e preservar e redefinir o estado.