问题
I want to calculate total and subtotal using a field array like input date.
This is my renderDetail Component:
renderDetail = ({fields, meta: { error,submitFailed}}) => (
<dl>
<dt>
<button type="button" className= 'btn btn-primary' onClick={() =>
fields.push()}>Add Detail</button>
{submitFailed && error && <span>{error}</span>}
</dt>
{ fields.map((detailRegister, index) =>
<dd key={index}>
<br></br>
<button className= 'btn btn-light mr-2'
type="button"
title="Remove detail"
onClick={() => { fields.remove(index)
if(fields.length == 0 || fields.length === undefined){
}
try{
for(let x in fields){
fields.remove(index)
let d = fields.selectedIndex;
if(fields.remove(index) && d >= 1 && d< fields.length ){
fields.removeAll(index);
}
}
}catch{console.info("deletes non numeric index")}
}}> Delete </button>
<h4>DetailRegister #{index + 1}</h4>
<Field
id={`${detailRegister}._id`}
name={`${detailRegister}.quantity`}
component= {NumberPickerInteger}
placeholder= '...quantity'
label = "Quantity"
/>
<br></br>
<h3><b>Product</b></h3>
<Field
id={`${registerDetail}._id`}
name={`${registerDetail}.product.code`}
type="number"
component= {RenderFieldNumeric}
placeholder='...product's code'
label = "Product's code"
/>
<Field
id={`${registerDetail}._id`}
name={`${registerDetail}.product.name`}
type="text"
component= {RenderField}
placeholder='...product's name'
label = "Product's name"
/>
<Field
id={`${registerDetail}._id`}
name={`${registerDetail}.product.price`}
component= {NumberPickerr}
placeholder= '...Price'
label = "product's price"
/>
<br></br>
<h3><b>Subtotal</b></h3>
<Field
id={`${registerDetail}._id`}
name={`${registerDetail}.subtotal`}
component= {SubtotalWidget}
placeholder= '...subtotal'
label = "Subtotal"
/>
</dd>
)
}
{error && <dt className="error">{error}</dt>}
</dl>
);
These are the formulas to calculate subtotal and total:
const calculatedSubtotal = (detail) =>{
detail = [];
const subtotals = [];
detail.map((detailItem,index) =>{
subtotals[index] = detailItem[index].quantity * detailItem[index].product.price;
return subtotals[index];
})
}
const calculatedTotal = (detail) =>{
detail = [];
let total = 0;
const subtotals = [];
detail.map((detailItem,index) =>{
subtotals[index] = detailItem[index].quantity * detailItem[index].product.price;
total += subtotals[index];
})
return total;
}
These are my lifecycle components willReceiveProps, componentDidUpdate and shouldComponentUpdate from BillForm class component:
componentWillReceiveProps = nextProps => {
// Load Contact Asynchronously
const { bill } = nextProps;
const { change, detail } = nextProps;
if (bill._id !== this.props.bill._id) {
// Initialize form only once
this.props.initialize(bill);
this.isUpdating = true;
}
if(this.props.renderDetail !== nextProps.renderDetail){
change(`detail[${this.props.index}].subtotal`,calculatedSubtotal(detail));
change('total',calculatedTotal(detail));
}
};
componentDidUpdate(prevProps,prevState,snapShot){
const {change} = prevProps;
const {detail} = prevProps;
if(this.props.detail !== prevProps.detail){
change(`detail[${this.props.index}].subtotal`,calculatedSubtotal(detail));
change('total',calculatedTotal(detail));
}
}
shouldComponentUpdate(nextProps, nextState) {
return this.props.detail !== nextProps.detail
}
This is my render when I getting components in form:
render(){
const { handleSubmit, loading,submitting, pristine, reset} = this.props;
if (loading) {
return <span>Loading...</span>;
}
return (
<form onSubmit={handleSubmit}>
<div>Detail:</div>
<FieldArray
name='detail'
component={this.renderDetail}
label='Detail'
/>
<Field
name='total'
component={TotalWidget}
placeholder= '...total'
label='Total'
/>
<Link className='btn btn-light mr-2' to='/bills'>
Cancel
</Link>
<button className='btn btn-primary mr-2' type='submit'>
{this.isUpdating ? 'Update' : 'Create'}
</button>
</form>
);
}
}
And here I'm using formValueSelector to change state and getting total and subtotal using fieldArray called "detail":
const valueSelector = formValueSelector('bill');
const makeStateToProps = () =>{
const mapStateToProps = (state,props) =>{
return {
detail: valueSelector(state,
`detail[${props.index}].quantity`,`detail[${props.index}].product.price`,
`detail[${props.index}].subtotal`
)
}
}
return mapStateToProps;
}
Connecting makeStateToProps to reduxForm:
BillForm = reduxForm(
{
form: 'bill',
enableReinitialize: false,
validate: validations
},
makeMapStateToProps
)(BillForm)
const mapDispatchToProps = undefined;
BillForm = connect(makeMapStateToProps,mapDispatchToProps)(BillForm);
I want calculate Subtotal and total accessing specifies fields from fieldArray using generic specify index.
I run code but changes are not reflected. I can't see subtotal and total calculated from detail.quantity, detail.product.price and detail.subtotal, respectively.
What is wrong?, I need to solve this.
I need you do a working demo for this case.
来源:https://stackoverflow.com/questions/60230808/how-to-calculate-total-and-subtotal-in-redux-form-using-formvalueselector