title: Is using useImperativeHandle hook justified here with Draft.JS editor and Formik?
body: <p>I'm making a small CMS system in React and I have a form where users can use the Draft.js editor along with some other fields.  For the question in mind, let's focus on the edit form.</p>
  <p>The code for the editor looks like this:</p>
  <pre class="lang-js prettyprint-override"><code>import React, { useRef } from 'react';
  import { Formik } from &quot;formik&quot;;
  import TextInputField from &quot;@/components/TextInputField&quot;;
  import client from &quot;@/utils/http&quot;;
  
  const MyForm = ({title, content}) =&gt; {
     const editorRef = useRef();
    
    function handleSubmit(values) {
       const editorContent = editorRef.current.parse();
       
       client.submit('/api/edit/project', { editorContent, ...values });
    }
  
    return (
      &lt;Formik onSubmit={formik.handleSubmit} initialValues={{ title }}&gt;
       {
         (formik) =&gt; (
             &lt;form onSubmit={formik.handleSubmit}&gt;
                &lt;TextInputField label=&quot;title&quot; name=&quot;title&quot; /&gt;
  
                &lt;RichEditor ref={editorRef} content={content} /&gt;
             &lt;/form&gt;
       )}
    &lt;/Formik&gt;);
  }
  
  </code></pre>
  <p>And I have the editor code:</p>
  <pre class="lang-js prettyprint-override"><code>import React, { useImperativeHandle, useState } from &quot;react&quot;;
  import {
    Editor,
    EditorState,
    convertFromHTML,
    ContentState,
    convertToRaw,
  } from &quot;draft-js&quot;;
  import draftToHtml from &quot;draftjs-to-html&quot;;
  
  function createFromContent(htmlContent) {
    const blocksFromHtml = convertFromHTML(htmlContent);
  
    const editorState = ContentState.createFromBlockArray(
      blocksFromHtml.contentBlocks,
      blocksFromHtml.entityMap
    );
  
    return EditorState.createWithContent(editorState);
  }
  
  function formatToHTML(editorState) {
    const raw = convertToRaw(editorState.getCurrentContent());
    const markup = draftToHtml(raw);
    return markup;
  }
  
  function RichEditor({ content = null }, ref) {
    const [editorState, setEditorState] = useState(() =&gt;
      content ? createFromContent(content) : EditorState.createEmpty()
    );
  
    useImperativeHandle(
      ref,
      () =&gt; ({
        parse: () =&gt; {
          return formatToHTML(editorState);
        },
      }),
      [editorState]
    );
  
    return (
      &lt;div className=&quot;App-Rich-Editor w-full block border border-gray-300 rounded-md mt-4 shadow-sm&quot;&gt;
        &lt;Editor
          placeholder=&quot;Enter your content...&quot;
          editorState={editorState}
          onChange={setEditorState}
        /&gt;
      &lt;/div&gt;
    );
  }
  
  export default React.forwardRef(RichEditor);
  </code></pre>
  <p>This <strong>works</strong>, but it brings me to the following questions and hence why asking the community because using <code>useImperativeHandle</code> seems like a &quot;hack&quot;. Since even the React documentation discourages the use of it.</p>
  <blockquote>
  <p>As always, imperative code using refs should be avoided in most cases.</p>
  </blockquote>
  <p>Since I wanted to format the editor's internal state <strong>only once</strong>, when I submit the form, is the code I shown justified even though it &quot;swims against the react tide&quot;, by using the imperative handle to share the child state with the parent.</p>
  <p>This brings me to the questions:</p>
  <ul>
  <li>Is it okay to <code>useImperativeHandle</code> hook in this case, for &quot;optimization&quot; so we grab the state only when we need to?</li>
  <li>Is there some better way to achieve this implementation with &quot;usual&quot; patterns, like &quot;lifting state up&quot;, &quot;render props&quot; or something else?</li>
  <li>Am I overlooking the problem here, and should I just bite the bullet and sync the entire editor state with <code>formik</code>, by lifting it up from the component, and then format it on submit?</li>
  </ul>
  <p>To me, the third option seems to break the separation of concerns, as it would pollute the <code>Form</code> context with state logic that just feels like it doesn't belong there.</p>