Draft.js フォーカスとstyle編

公開:2021/02/14
更新:2021/02/15
2 min読了の目安(約2500字TECH技術記事

はじめに

https://zenn.dev/enish/articles/4804d2d59d75e2
の続きです
スタイルをボタンで変更する機能を実装しようとして再びはまったため記事にしてみました。
今回はfocusとボタンのイベント発火のタイミングのお話しです。

何にはまったのか

テキスト入力のスタイルをRichUtilsをつかってトグルしたりできてよいね、というのがウリかと思うのですが、ボタンは押せどもスタイルが切り替わらずという状態になったというお話しです。

うまく動かないコード

抜粋ですが、こんなコードを書いてました
editorEnableあたりは前回の記事のお話しで、SSR時にエラーを抑制するためのコードです。
これだと入力中のテキストを選択してボタンを押せば太字になりますが、ボタンを押してから入力をしに行っても太字になりません。

  const handleBoldClick = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
    event.preventDefault()
    setEditorState(RichUtils.toggleInlineStyle(editorState, "BOLD"))
  }

  return (
    <div>
      {editorEnable && (
        <>
        <button onClick={handleBoldClick}>Bold</button>
        <Editor
          placeholder="Write something!"
          editorKey="test-key"
          editorState={editorState}
          onChange={setEditorState}
        />
        </>
      )}
    </div>
  );

問題点

https://stackoverflow.com/questions/49831728/clicking-on-button-is-not-adding-inline-style-using-draft-js
こちらに答えがありました。
onClick時には入力部からfocusが飛んでいるのが問題だよ、と。
また、Boldボタンを押したあとにテキストにフォーカスを戻したいので
https://stackoverflow.com/questions/61928674/using-draft-js-mention-plugin-with-react-hooks
こちらを参考に入力部をdivタグで囲んでonclickイベントをつかってfocusをEditorコンポーネントに戻す、という形に書き換えてみました。

This is a pretty basic Draft-JS implementation

とのこと。

修正後のコード

以下のコードで意図したとおりボタンを押すたびにBoldかどうかのスタイルが切り替わるようにできました。

import React, { useEffect, useRef, useState } from 'react'
import {Editor, EditorState, RichUtils} from 'draft-js';
import 'draft-js/dist/Draft.css'

const DraftJSEditor = () => {
  const [editorEnable, setEditorEnable] = useState(false)
  const [editorState, setEditorState] = useState(() => 
    EditorState.createEmpty()
  );
  const editorRef = useRef<Editor>(null)

  useEffect(() => {
    setEditorEnable(true)
  }, [])

  const handleBoldClick = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
    event.preventDefault()
    setEditorState(RichUtils.toggleInlineStyle(editorState, "BOLD"))
  }

  return (
    <div onClick={() => {editorRef.current?.focus()}}>
      {editorEnable && (
        <>
        <button onMouseDown={handleBoldClick}>Bold</button>
        <Editor
          ref={editorRef}
          placeholder="Write something!"
          editorKey="test-key"
          editorState={editorState}
          onChange={setEditorState}
        />
        </>
      )}
    </div>
  );
}

おわりに

なんとなくfanctinal componentで書いていこうとしたら何度もはまる結果となってしまいました。
これでようやくスタートラインに立てたのではないかなと思います。
今後ももしもはまりどころがあったら記事にするかもしれません。