Redux表单:如果验证成功,则更改其他字段

时间:2018-02-21 16:45:21

标签: reactjs redux redux-form reselect

我正在使用React Redux,Redux-form并重新选择库(https://github.com/reactjs/reselect)。

我有一个包含两个字段的组件:id sequence card_tap time 1 1 61 1 1 1 62 10 2 12 62 10 2 12 61 20 quota。我想根据amount字段更新amount字段。对于quota的计算,我使用amountselector

我希望仅在有效reselect时更新amount字段。

我试过没有成功的quota字段道具,因为它是在选择器之前执行的。

我发现的最佳解决方案是使用onChange reduxForm()属性,因为它在选择器之后执行但我在验证后无法运行。

这是我的代码:

onChange

1 个答案:

答案 0 :(得分:2)

Here's a working CodeSandbox

答案是使用formValueSelector并在componentWillReceiveProps(或componentDidUpdate)中更新。以下是工作Modal.js的版本。请注意,quota验证在验证函数和计算中都会重复使用。

import React, { Component } from 'react'
import { connect } from 'react-redux'
import { Field, reduxForm, formValueSelector } from 'redux-form'

const validateQuota = quota => {
  if (quota <= 1) {
    return 'The quota must be greater than 1'
  } else if (quota > 50) {
    return 'The quota must be less than 50'
  }
}

const validate = values => {
  const errors = {}
  errors.quota = validateQuota(values.quota)
  return errors
}

/**
 * Arbitrary function that takes quota and calcuates amount.
 * For the purposes of this demo, I'm assuming that we're a
 * mobile phone company and are charging $19.95 per 5 GB of quota.
 */
const calculateAmount = quota => Math.ceil(quota / 5) * 19.95

class Modal extends Component {
  renderField = ({ input, label, type, meta: { touched, error } }) => (
    <div>
      <input {...input} type={type} placeholder={label} />
      {touched && error && <span>{error}</span>}
    </div>
  )

  componentWillReceiveProps(nextProps) {
    const { change, quota } = nextProps
    if (this.props.quota !== nextProps.quota && !validateQuota(quota)) {
      // quota value is valid
      change('amount', calculateAmount(quota))
    }
  }

  render() {
    return (
      <div>
        <label>Quota</label>
        <Field
          name="quota"
          component={this.renderField}
          type="number"
          label="Quota"
        />
        <label>Amount</label>
        <Field
          name="amount"
          component={this.renderField}
          type="number"
          label="Amount"
        />
      </div>
    )
  }
}

const valueSelector = formValueSelector('modal') // <-- form name

const makeMapStateToProps = () => {
  const mapStateToProps = state => {
    return {
      quota: valueSelector(state, 'quota'),
      initialValues: {
        // Not implementing the modal reducer...
        // quota: state.modal.quota,
        // amount: state.modal.amount
      }
    }
  }
  return mapStateToProps
}

Modal = reduxForm(
  {
    form: 'modal',
    enableReinitialize: true,
    validate
  },
  makeMapStateToProps
)(Modal)

const mapDispatchToProps = undefined // not included in StackOverflow snippet

Modal = connect(makeMapStateToProps, mapDispatchToProps)(Modal)

export default Modal