2017-08-04 61 views
1

我正在构建一个表单 - 用户在移动到下一个屏幕之前需要回答的一系列问题(单选按钮)。对于字段验证,我使用yup(npm包)和redux作为状态管理。反应 - 检查元素是否在DOM中可见

对于一个特定的场景/组合,新的屏幕(div)显示要求确认(复选框),然后用户才能继续。我只想在显示时应用此复选框的验证。

如何检查元素(div)是否使用React显示在DOM中?

我认为这样做的方式是将varibale'isScreenVisible'设置为false,如果条件满足,我会将状态更改为'true'。

我正在做检查并在_renderScreen()中将'isScreenVisible'设置为true或false,但由于某种原因它会进入无限循环。

我的代码:

class Component extends React.Component { 

    constructor(props) { 
    super(props); 

    this.state = { 
     formisValid: true, 
     errors: {}, 
     isScreenVisible: false 
    } 

    this.FormValidator = new Validate(); 
    this.FormValidator.setValidationSchema(this.getValidationSchema()); 
    } 

    areThereErrors(errors) { 
    var key, er = false; 
    for(key in errors) { 
     if(errors[key]) {er = true} 
    } 
    return er; 
    } 

    getValidationSchema() { 
    return yup.object().shape({ 
     TravelInsurance: yup.string().min(1).required("Please select an option"), 
     MobilePhoneInsurance: yup.string().min(1).required("Please select an option"), 
     Confirmation: yup.string().min(1).required("Please confirm"), 
    }); 
    } 

    //values of form fields 
    getValidationObject() { 
    let openConfirmation = (this.props.store.Confirmation === true)? 'confirmed': '' 

    return { 
     TravelInsurance: this.props.store.TravelInsurance, 
     MobilePhoneInsurance: this.props.store.MobilePhoneInsurance, 
     Confirmation: openConfirmation, 
    } 
    } 

    setSubmitErrors(errors) { 
    this.setState({errors: errors}); 
    } 

    submitForm() { 
    var isErrored, prom, scope = this, obj = this.getValidationObject(); 
    prom = this.FormValidator.validateSubmit(obj); 

    prom.then((errors) => { 
     isErrored = this.FormValidator.isFormErrored(); 

     scope.setState({errors: errors},() => { 
     if (isErrored) { 
     } else { 
      this.context.router.push('/Confirm'); 
     } 
     }); 
    }); 
    } 

    saveData(e) { 
    let data = {} 
    data[e.target.name] = e.target.value 

    this.props.addData(data) 

    this.props.addData({ 
     Confirmation: e.target.checked 
    }) 
    } 

    _renderScreen =() => { 
    const { 
     Confirmation 
    } = this.props.store 

    if(typeof(this.props.store.TravelInsurance) !== 'undefined' && typeof(this.props.store.MobilePhoneInsurance) !== 'undefined') && 
    ((this.props.store.TravelInsurance === 'Yes' && this.props.store.MobilePhoneInsurance === 'No') || 
    (this.props.store.TravelInsurance === 'No' && this.props.store.MobilePhoneInsurance === 'Yes')){ 

     this.setState({ 
      isScreenVisible: true 
     }) 

      return(
      <div> 
       <p>Please confirm that you want to proceed</p> 

        <CheckboxField 
        id="Confirmation" 
        name="Confirmation" 
        value={Confirmation} 
        validationMessage={this.state.errors.Confirmation} 
        label="I confirm that I would like to continue" 
        defaultChecked={!!Confirmation} 
        onClick={(e)=> {this.saveData(e)} } 
        /> 
       </FormLabel> 
      </div> 
     ) 
     } 
     else{ 
     this.setState({ 
      isScreenVisible: false 
     }) 
     } 
    } 

    render(){ 
    const { 
     TravelInsurance, 
     MobilePhoneInsurance 
    } = this.props.store 

    return (
     <div>   
      <RadioButtonGroup 
      id="TravelInsurance" 
      name="TravelInsurance" 
      checked={TravelInsurance} 
      onClick={this.saveData.bind(this)} 
      options={{ 
       'Yes': 'Yes', 
       'No': 'No' 
      }} 
      validationMessage={(this.state.errors.TravelInsurance) ? this.state.errors.TravelInsurance : null } 
      /> 

     <RadioButtonGroup 
      id="MobilePhoneInsurance" 
      name="MobilePhoneInsurance" 
      checked={MobilePhoneInsurance} 
      onClick={this.saveData.bind(this)} 
      options={{ 
      'Yes': 'Yes', 
      'No': 'No' 
      }} 
      validationMessage={(this.state.errors.MobilePhoneInsurance) ? this.state.errors.MobilePhoneInsurance : null } 
     /> 

     this._renderScreen() 

     <ButtonRow 
      primaryProps={{ 
       children: 'Continue', 
       onClick: e=>{ 
       this.submitForm(); 
      } 
     }} 
     </div> 
    ) 
    } 
} 

const mapStateToProps = (state) => { 
    return { 
    store: state.Insurance, 
    } 
} 

const Insurance = connect(mapStateToProps,{addData})(Component) 

export default Insurance 

回答

3

您可以将裁判要检查它是否对视,然后有类似的元素:

/** 
    * Check if an element is in viewport 
    * 
    * @param {number} [offset] 
    * @returns {boolean} 
    */ 
    isInViewport(offset = 0) { 
    if (!this.yourElement) return false; 
    const top = this.yourElement.getBoundingClientRect().top; 
    return (top + offset) >= 0 && (top - offset) <= window.innerHeight; 
    } 


    render(){ 

    return(<div ref={(el) => this.yourElement = el}> ... </div>) 

    } 

您可以将监听器比如onScroll,并检查元素何时位于视口上。

您还可以使用Intersection Observer API with a polyfil或使用HoC component that does the job

相关问题