Redux 表单:如果验证成功则更改其他字段
Redux form: change other field if validation success
我正在使用 React Redux、Redux 形式和重新选择库 (https://github.com/reactjs/reselect)。
我有一个包含两个字段的组件:quota
和 amount
。我想根据 quota
字段更新 amount
字段。对于 amount
的计算,我使用 selector
和 reselect
。
我只想更新 amount
字段,前提是它有效 quota
。
我试过没有成功 onChange
field props 因为它在选择器之前执行。
我找到的最佳解决方案是使用 onChange
reduxForm() 属性 因为它是在选择器之后执行的,但我无法在验证后 运行
这是我的代码:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { makeModalData } from '../selectors/Modal';
import { change, Field, reduxForm, formValueSelector } from 'redux-form';
const validate = values => {
const errors = {};
if (values.quota <= 1) {
errors.quota = "The quota must be greater than 1";
} else if (values.quota > 50) {
errors.quota = "The quota must be less than 50";
}
return errors;
}
const updateForm = (values, dispatch, props, previousValues) => {
if (props.valid) { // this not work because it shows the previous state of validation
if (values.quota !== previousValues.quota) {
let amount = props.modal_data.amount; // data with reselect
dispatch(change('modal', 'amount', amount));
}
}
}
class Modal extends Component {
constructor(props) {
super(props);
}
renderField = ({ input, label, type, meta: { touched, error } }) => (
<div>
<input {...input} type={type} placeholder={label} />
{touched && error && <span>{error}</span>}
</div>
)
// this not work because is executed before selector
/*
updateAmount(event) {
let amount = this.props.modal_data.amount;
this.props.dispatch(change('modal', 'amount', amount));
}*/
render() {
return (
<label>Quota</label>
<Field
name="quota"
component={this.renderField}
type="number"
label="Quota"
/*onChange={this.updateAmount.bind(this)} */
/>
<label>Amount</label>
<Field
name="amount"
component={this.renderField}
type="number"
label="Amount"
/>
)
}
}
const makeMapStateToProps = () => {
const modal_data = makeModalData(); // selector
const mapStateToProps = state => {
let my_modal_data = modal_data(state, state.modal)
return {
initialValues: {
quota: state.modal.quota,
amount: state.modal.amount,
},
}
}
return mapStateToProps;
}
Modal = reduxForm({
form: 'modal',
enableReinitialize: true,
touchOnChange: true,
validate,
onChange: updateForm
},makeMapStateToProps)(Modal);
Modal = connect(
makeMapStateToProps,
mapDispatchToProps
)(Modal);
export default Modal;
答案是使用 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 .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 Whosebug snippet
Modal = connect(makeMapStateToProps, mapDispatchToProps)(Modal)
export default Modal
我正在使用 React Redux、Redux 形式和重新选择库 (https://github.com/reactjs/reselect)。
我有一个包含两个字段的组件:quota
和 amount
。我想根据 quota
字段更新 amount
字段。对于 amount
的计算,我使用 selector
和 reselect
。
我只想更新 amount
字段,前提是它有效 quota
。
我试过没有成功 onChange
field props 因为它在选择器之前执行。
我找到的最佳解决方案是使用 onChange
reduxForm() 属性 因为它是在选择器之后执行的,但我无法在验证后 运行
这是我的代码:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { makeModalData } from '../selectors/Modal';
import { change, Field, reduxForm, formValueSelector } from 'redux-form';
const validate = values => {
const errors = {};
if (values.quota <= 1) {
errors.quota = "The quota must be greater than 1";
} else if (values.quota > 50) {
errors.quota = "The quota must be less than 50";
}
return errors;
}
const updateForm = (values, dispatch, props, previousValues) => {
if (props.valid) { // this not work because it shows the previous state of validation
if (values.quota !== previousValues.quota) {
let amount = props.modal_data.amount; // data with reselect
dispatch(change('modal', 'amount', amount));
}
}
}
class Modal extends Component {
constructor(props) {
super(props);
}
renderField = ({ input, label, type, meta: { touched, error } }) => (
<div>
<input {...input} type={type} placeholder={label} />
{touched && error && <span>{error}</span>}
</div>
)
// this not work because is executed before selector
/*
updateAmount(event) {
let amount = this.props.modal_data.amount;
this.props.dispatch(change('modal', 'amount', amount));
}*/
render() {
return (
<label>Quota</label>
<Field
name="quota"
component={this.renderField}
type="number"
label="Quota"
/*onChange={this.updateAmount.bind(this)} */
/>
<label>Amount</label>
<Field
name="amount"
component={this.renderField}
type="number"
label="Amount"
/>
)
}
}
const makeMapStateToProps = () => {
const modal_data = makeModalData(); // selector
const mapStateToProps = state => {
let my_modal_data = modal_data(state, state.modal)
return {
initialValues: {
quota: state.modal.quota,
amount: state.modal.amount,
},
}
}
return mapStateToProps;
}
Modal = reduxForm({
form: 'modal',
enableReinitialize: true,
touchOnChange: true,
validate,
onChange: updateForm
},makeMapStateToProps)(Modal);
Modal = connect(
makeMapStateToProps,
mapDispatchToProps
)(Modal);
export default Modal;
答案是使用 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 .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 Whosebug snippet
Modal = connect(makeMapStateToProps, mapDispatchToProps)(Modal)
export default Modal