@ka2n

Technology and beer

ReactコンポーネントからRailsのフォームの送信ボタンを無効化する

Railsベースのフォームの中に一部の入力欄でReactコンポーネントを使うことが稀にあるかもしれません。

入力欄がinvalidな状態なのに送信ボタンはReact外で困る。。。

そいういった時は、さくっと送信ボタンのDOMを探して操作しても良いですが、Rails自体(rails-ujs)の仕組みを利用することで再利用性が上がると思います。

以下のコード例のようにhookを作成し、Reactコンポーネントでのバリデーション状態を元に送信ボタンを有効化/無効化しています。(別にhooksじゃなくてnullを返すコンポーネントでももちろん良いです。)

import Rails from "@rails/ujs"
import { useEffect, useRef } from "react"

/** Railsのフォームの送信ボタンを@rails/ujsを使って有効/無効化します
 */
export const useRailsFormValidation = (valid: boolean) => {
  const containerRef = useRef<HTMLInputElement>(null)
  useEffect(() => {
    if (!containerRef.current) return

    const form = containerRef.current.form
    valid ? Rails.enableElement(form) : Rails.disableElement(form)
  }, [valid])

  return {
      containerRef,
  }
}

使用時はこんな感じ

const VeryComplexInput:  React.FC<...> = props => {
  const { valid, onChange, value, ..... } = useSomeForm({...}) // フォームのイベントハンドリングをしていると想定

  const { containerRef } = useRailsFormValidation(valid)
  return (
    <>
      <input type="hidden" ref={containerRef} /> // フォームを探すためのinput
      ....
    </>
  )
}