← Toda a documentação

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 key baseada 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.