LoginSignup
4
1

More than 5 years have passed since last update.

redux-formでSubmissionErrorを使わずにエラーを表示する

Last updated at Posted at 2018-07-28

reactを使って開発することが多いのですが、
adminサイトなどではよくredux-formを使ったりしています。

サーバからのエラー等は、公式ドキュメントの通りに
redux-formのhandleSubmitの中でSubmissionErrorを投げてあげれば大体は上手くいくんですが……

残念ながら、既存の改修でハチャメチャが押し寄せてくる状態であったり、
dispatchの中の処理でAPI投げているのでSubmmisonErrorが取れない!とか、
上手くいかない場合が多々あったので、自由にエラーを設定できないか試してみました。

こうするともっと上手くいくよ!というのがあればコメント等もらえると。

作ってみたもの

custom_error.gif

Log Inを押した時には、実際のサーバエラー想定の結果を、
Set Errorを押した時には全く関係ない場所から、redux-formの各項目に対してエラーを設定しています。

demo

repository

redux-form document

https://redux-form.com/7.4.2/examples/submitvalidation/
https://redux-form.com/7.4.2/docs/api/actioncreators.md/

実装内容

import React from 'react';
import { connect } from 'react-redux';
import {
  Field,
  reduxForm,
  SubmissionError,
  stopSubmit as stopSubmitAction,
} from 'redux-form';
import compose from 'recompose/compose';

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

const renderField = ({ input, label, type, meta: { touched, error } }) => (
  <div>
    <label>{label}</label>
    <div>
      <input {...input} placeholder={label} type={type} autoComplete="off" />
      {touched && error && <span>{error}</span>}
    </div>
  </div>
);

const AppForm = (props) => {
  const {
    error,
    handleSubmit,
    pristine,
    reset,
    submitting,
    touch,
    stopSubmit,
  } = props;

  return (
    <form onSubmit={handleSubmit(() => {
      return sleep(1000).then(() => {
        throw new SubmissionError({
          password: 'Wrong password',
          _error: 'Login failed!'
        })
      });
    })}>
      <Field
        name="username"
        type="text"
        component={renderField}
        label="Username"
      />
      <Field
        name="password"
        type="password"
        component={renderField}
        label="Password"
      />
      {error && <strong>{error}</strong>}
      <div>
        <button type="submit" disabled={submitting}>
          Log In
        </button>
        <button
          type="button"
          disabled={pristine || submitting}
          onClick={reset}
        >
          Clear Values
        </button>
        <button
          type="button"
          disabled={submitting}
          onClick={() => {
            touch(...['username', 'password']);
            stopSubmit('app-form', {
              username: '話は聞かせてもらった',
              password: '人類は滅亡する!',
              _error: 'な……なんだってー!!'
            })
          }}
        >
          Set Error
        </button>
      </div>
    </form>
  );
};

const enhance = compose(
  reduxForm({ form: 'app-form' }),
  connect(null, {
    stopSubmit: stopSubmitAction
  }),
);

export default enhance(AppForm);

内容は簡単、stopSubmitとtouchを使っているだけです。

redux-formのソースを読んでみると一発なんですが、
SubmissionErrorをthrowした先で、stopSubmit関数を呼んであげています。
この関数に対してエラーデータを渡しているので、自由に呼びたい場合には、
それと同様に呼び出したい場所でstopSubmitを実行すればOKです。
※touchしておかないと、カーソルを合わせる前にボタンを押した際に正常に動かないのでそこだけ注意が必要です。

今回はボタンを押下したタイミングで呼び出していますが、reducerの中の処理でもどこでも実装は可能です。
reducerの処理の中でやるのが適切かどうかは置いておきますが……

最後に

株式会社ネコカリでは猫の手も借りたい🔥炎上中🔥なお仕事を募集しています!
一緒に働くメンバーも募集していますので、よかったら是非!

4
1
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1