Feruza
Feruza

Reputation: 974

How to stop Editor draftJS cursor jumping to beginning of text while typing in React Hooks?

I have the problem with the drafjs plugin which is Editor, thing is it jumps to the beginning of the text when I am typing in the Editor. I have found How to stop DraftJS cursor jumping to beginning of text? this solution, but it is a bit different what I have in my code and in addition I made the component with new feature of React Hooks. Please, could you help me with this issue.

import {
  EditorState, ContentState, convertToRaw,
} from 'draft-js'
import { Editor } from 'react-draft-wysiwyg'
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'
import draftToHtml from 'draftjs-to-html'
import htmlToDraft from 'html-to-draftjs'

export default ({ value, onChange }) => {
  const [editorState, setEditorState] = useState(EditorState.createEmpty())

  useEffect(() => {
    setEditorState(
      EditorState.push(
        editorState,
        ContentState.createFromBlockArray(
          htmlToDraft(value || ''),
        ),
      ),
    )
  }, [value])

  return (
    <div className="rich-editor">
      <Editor
        editorState={editorState}
        onEditorStateChange={onEditorStateChange}
        toolbar={{
          options: ['inline'],
          inline: {
            options: ['bold', 'italic', 'underline'],
          },
        }}
      />
    </div>
  )

  function onEditorStateChange(es) {
    setEditorState(es)

    const html = draftToHtml(convertToRaw(es.getCurrentContent()))
    if (value !== html) {
      onChange({ target: { name: 'text', value: html } })
    }
  }
}

For example, enter image description here

Upvotes: 3

Views: 3216

Answers (3)

Genesha Irzan Pratama
Genesha Irzan Pratama

Reputation: 61

add detail from my code:


export default function App(props) {
  const [state, setstate] = useState(EditorState.createEmpty());

  function toHtml(es) {
    return draftToHtml(convertToRaw(es.getCurrentContent())); // added
  }
  useEffect(() => {
    // check if reference value is null or empty
    // check if there is changes in content, prevent cursor keypress as input
    if (!props.value || toHtml(state) === props.value) return;
    setstate(
      EditorState.push(
        state,
        ContentState.createFromBlockArray(htmlToDraft(props.value || ""))
      )
    );
  }, [props.value]);

  function handleChange(raw) {
    // directly update local state
    setstate(raw);

    // check if there is changes in content, prevent cursor keypress as input
    // parent state updated only when content changes (without cursor)
    if (props.value !== toHtml(raw)) {
      props.onChange(draftToHtml(convertToRaw(raw.getCurrentContent())));
    }
  }

  return (
    <Editor
      editorState={state}
      onEditorStateChange={handleChange}
      placeholder={props.label}
      toolbar={{
        options: ["inline"],
        inline: { options: ["bold", "italic", "underline"] },
      }}
    />
  );
}

keyword code code as this :

toHtml(state) === props.value

this code preventing local state changes / parent value (onChange) updated on cusor keypresed

Upvotes: 0

Shivanand T
Shivanand T

Reputation: 1283

Another way is check if the value is empty

useEffect(() => {
  if (value === '') {
      onEditorStateChange(EditorState.createEmpty())
  }

}, [value === ''])

This way, when the value is empty, the editorstatechange is assigned once again as empty.. subsequent times it should work fine as it was initialised to empty and onEditorStateChange will not be called again from useEffect as value is not empty

Upvotes: 0

Feruza
Feruza

Reputation: 974

ok I kind of figure out myself. However, it is not the best solution. Basically, I am converting the updated text to Html type, then comparing the value with converted darft.js editorState. Shortly, here is my code, if it helps to anyone in the future

import React, { useEffect, useState } from 'react'
import {
  EditorState, ContentState, convertToRaw,
} from 'draft-js'
import { Editor } from 'react-draft-wysiwyg'
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'
import draftToHtml from 'draftjs-to-html'
import htmlToDraft from 'html-to-draftjs'

export default ({ value, onChange }) => {
  const [editorState, setEditorState] = useState(EditorState.createEmpty())

  useEffect(() => {
    if (toHtml(editorState) === value) return //added

    setEditorState(
      EditorState.push(
        editorState,
        ContentState.createFromBlockArray(
          htmlToDraft(value || ''),
        ),
      ),
    )
  }, [value])

  return (
    <div className="rich-editor">
      <Editor
        editorState={editorState}
        onEditorStateChange={onEditorStateChange}
        toolbar={{
          options: ['inline'],
          inline: {
            options: ['bold', 'italic', 'underline'],
          },
        }}
      />
    </div>
  )

  function onEditorStateChange(es) {
    setEditorState(es)
    const html = toHtml(es) //added
    if (value !== html) {
      onChange({ target: { name: 'text', value: html } })
    }
  }

  function toHtml(es) {
    return draftToHtml(convertToRaw(es.getCurrentContent())) // added
  }
}

Upvotes: 3

Related Questions