LoginSignup
0
2

More than 5 years have passed since last update.

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

Posted at

ソースは以下
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')
);

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

0
2
0

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
0
2