over 3 years ago

這邊是搭配 Redux 及 react-bootstrap 做整合驗證
可修改HOC state 狀態來做變化
此範例產生的 state 範本
{ac:'{success | error}', acErroe:'{取至 error }'...}

import React from 'react';
import { findDOMNode } from 'react-dom';
import Immutable from 'immutable';

const ValidateForm = (Component, extendValidateMethods, validateItemIds) => class extends React.Component {
  constructor(props) {
    super(props);
    // 執行驗證函數
    this._checkForm = this._checkForm.bind(this);
    // 預設的驗證函數 固定參數 傳入主Component 及 要驗證的 子Component
    let _defaultValidateMethods = {
      empty: function (mainComponent, checkComponent) {
            let dom = findDOMNode(checkComponent);
            let val = dom.value;
            if(val == "") {
                return false;
            }
            var regu = "^[ ]+$";
            var re = new RegExp(regu);

            return !re.test(val);
        }
    }
    // 加入擴充函數 extendValidateMethods 可預設傳入 {}
    this._validateMethodSettings =  Object.assign(_defaultValidateMethods, extendValidateMethods);

    // 運用 Immutable 配合 validateItemIds 建立 HOC state
    let valstateImmutable = Immutable.Map({});
    for (let itemId of validateItemIds) {
       valstateImmutable = valstateImmutable.set(itemId, 'success');
       valstateImmutable = valstateImmutable.set(itemId + 'Error','');
    }
    this.state = {valstates: valstateImmutable};
  }
  _checkForm(e) {
    let component = this.refs.checkComponent;
    let state = this.state.valstates;
    let check = false;
    for (let itemId of validateItemIds) {
      // 取出要執行驗證的 checkMethod
      let runValidateMethod = this._validateMethodSettings[component.refs[itemId].props.checkMethod];
      // 執行 checkMethod 傳入主Component 及 要驗證的 子Component
      let result = runValidateMethod(component, component.refs[itemId]);
      let error = component.refs[itemId].props.error;
      // 設定錯誤或成功狀態
      if(!result) {
        state = state.set(itemId, 'error');
        state = state.set(itemId + 'Error',error);
        this.setState({valstates : state});
        check = true;
      } else {
        state = state.set(itemId, 'success')
        this.setState({valstates : state.set(itemId, 'success')});
      }
    }

    return check;
  }
  render() {
    return <Component ref="checkComponent" {...this.props} {...this.state} checkForm={this._checkForm} />
  }
}

export default ValidateForm;

使用範例

import { findDOMNode } from 'react-dom';
...
..
.

class Main extends Component {
  constructor(props) {
    super(props);
    this._onLogin = this._onLogin.bind(this);
  }
  _onLogin(e) {
    // 執行驗證 取得結果
    let check = this.props.checkForm();

    if (check) {
      return;
    }
    let acDom = findDOMNode(this.refs.ac);
    let pwDom = findDOMNode(this.refs.pw);
    this.props.actions.login(acDom.value, pwDom.value);
    this.props.actions.loginCheck();
  }
  render() {
    ....
    ...
    ..
    .
    // 提供 ref={驗證Id} checkMethod={驗證函數名稱} error={錯誤訊息}
    // this.props.valstates.get('ac') 取得驗證狀態 
    // this.props.valstates.get('acError') 取得錯誤訊息 取至 error="請輸入姓名"
    return (
      <form>
        <FormGroup controlId="formValidationError1" validationState={this.props.valstates.get('ac')}>
           <ControlLabel>帳號</ControlLabel>
           <FormControl type="text"  placeholder={this.props.valstates.get('acError')} ref="ac" checkMethod="empty"  error="請輸入姓名" />
       </FormGroup>
       <FormGroup controlId="formValidationError2" validationState={this.props.valstates.get('pw')}>
          <ControlLabel>密碼</ControlLabel>
          <FormControl type="password" placeholder={this.props.valstates.get('pwError')} ref="pw" checkMethod="compare" CompareId="ac" error="請輸入密碼"  />
      </FormGroup>
        <Button bsStyle="primary" onClick={this._onLogin}>登入</Button>
        {(isLoading) ? <div>load....</div> : <div>{msg}</div>}
      </form>
    );
  }
}

....
...
..
.
// 建立擴充驗證
const extendValidateMethods = {
  compare : (mainComponent, checkComponent) =>{
    let checkDom = findDOMNode(checkComponent);
    let compareDom = findDOMNode(mainComponent.refs[checkComponent.props.CompareId]);
    alert(`${checkDom.value} : ${compareDom.value}`);
    return false;
  }
};
// 建立檢查欄位Id (ref="ac")
const validateItemIds = ['ac', 'pw'];

// 搭配 redux 傳入 HOC ValidateForm, 如無 extendValidateMethods時可傳入 {}
export default connect(makeMapStateToProps, mapDispatchToProps)(ValidateForm(Main, extendValidateMethods, validateItemIds));

執行結果
預設 empty method

擴充 compare method

← 避開 anti-pattern 造成的 re-render 使用 Webpack modulesDirectories 來消除相對路徑配置 →
 
comments powered by Disqus