Help us understand the problem. What is going on with this article?

React Redux でvalidatorjsを使ったHOC Validationを作る

More than 1 year has passed since last update.

ソースは以下
https://github.com/ichi944/with-validation/tree/master/src

動機

  • react-redux でいい感じのバリデーションはないか?
  • redux-form -> 覚えることがたくさんありそう(特に他のUIライブラリとの連携など)
  • 上記の理由からコンポーネントとして実装されているやつはやめたい
  • Laravelに馴染みがあるのでバリデーションルールを同じ感じで書きたい
  • VueにはVee-Validateという使いやすいやつがある
  • validatorjsというライブラリがあるがインターフェースがいまいちreactっぽくない
  • HOCで穏便すればいいのでは

実装

かいつまんでいうとwithValidatorでFormをラップすることによって

  • Form側にdirty, errorsというメンバーが生える
  • makeAllDirty(), makeValidator()メソッドが生える
  • HOCするときにオプションを2つ渡す
    • setData: propsからチェックする値を取り出す関数
    • rules: validatorjsに渡すバリデーションルール文字列
  • HOC内のcomponentDidUpdate時に対象の値が変更されていればバリデーションを行いFormにerrorsとdirtyを渡す
  • Formはerrorsとdirtyの値で適当にメッセージを表示したりなどする
  • SubmitのときはmakeValidator()でvalidatorjsのインスタンスが取得できるのでそれでなんとかする
//... 省略
import withValidator from './withValidator';
//... 省略

// Define Form
class Form extends Component {
  //... 省略
  render() {
    const { dirty, errors, email, password, handleChange } = this.props;
    const styles = {
      error: {
        color: 'red',
        fontSize: '0.8em',
      },
    };
    return (
      <div>
        <div>
          <label>email: </label>
          <input
            type="text"
            name="email"
            value={email}
            onChange={handleChange}
          />
          { dirty.email && errors.has('email') ?
            <span style={styles.error}>{errors.first('email')}</span> : null }
        </div>
        <div>
          <label>password: </label>
          <input
            type="password"
            name="password"
            value={password}
            onChange={handleChange}
          />
          { dirty.password && errors.has('password') ?
            <span style={styles.error}>{errors.first('password')}</span> : null }
        </div>
        <div><button onClick={this.handleSubmit}>送信</button></div>
      </div>
    );
  }
}

// Wrapp with Validator
const FormWithValidator = withValidator({
  setData: ({email, password}) => ({
    email,
    password,
  }),
  rules: {
    email: 'required',
    password: 'required|min:8',
  },
})(Form);

// Connect to Store
const mapStateToProps = ({email, password}) => ({
  email,
  password,
});

const mapDispatchToProps = (dispatch) => ({
  handleChange(e) {
    const { name, value } = e.target;
    dispatch({
      type: 'UPDATE_FORM',
      name,
      value,
    });
  }
});

const ConnectedForm = connect(mapStateToProps, mapDispatchToProps)(FormWithValidator);

// Mount
class App extends Component {
  render() {
    return (
      <div>
        <h1>Validator Form</h1>
        <ConnectedForm />
      </div>
    );
  }
}

render(
  <Provider store={store}><App /></Provider>,
  document.querySelector('#app')
);

残りはコード参照。
もっと色々できそうではあるのですが、窮屈になってきそうなのでここまでにとどめています。

ichi944
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away