当我单击按钮向表单添加新行时,我正在尝试向数组添加新对象。
import React, { useState, useEffect } from 'react';
import NumberFormat from 'react-number-format';
import { Button, Form, Label, Input } from 'reactstrap';
import RctCollapsibleCard from './RctCollapsibleCard/RctCollapsibleCard';
import LinearProgress from '../util/LinearProgress';
import * as tenantAPI from '../api/tenants';
const Test = (props) => {
const tenantName = props.tenantName;
const tenantTransactionID = props.selectedTransaction;
const propertyID = props.propertyID;
const [ loading, setLoading ] = useState(true);
const [ updated, setUpdated ] = useState(false);
const [ payments, setPayments ] = useState([]);
const [ categories, setCategories ] = useState([]);
const [ paymentAmount, setPaymentAmount ] = useState(0);
const [ currentTotal, setCurrentTotal ] = useState(0);
const [ showSave, setShowSave ] = useState(false);
useEffect(() => {
async function fetchData() {
console.log('load');
setLoading(true);
setPaymentAmount(parseFloat(await tenantAPI.getTransactionAmount(tenantTransactionID)));
//const allocated = await tenantAPI.getAllocatedPayments(tenantTransactionID);
//setPayments(allocated);
setCategories(await tenantAPI.getPaymentCategories(propertyID));
//let total = 0;
//for(const a of allocated) {
//total += parseFloat(a.PaymentAmount);
//}
//setCurrentTotal(total);
setLoading(false);
}
fetchData();
}, [tenantTransactionID, propertyID])
useEffect(() => {
console.log(payments);
if(parseFloat(paymentAmount).toFixed(2) === parseFloat(currentTotal).toFixed(2)) {
setShowSave(true);
} else {
setShowSave(false);
}
}, [updated]);
const handleCategoryChange = (val, index) => {
}
const handleAmountChange = (val, index) => {
}
const handleDelete = (index) => {
}
const addPayment = () => {
setPayments([
...payments,
{
PaymentAmount: 0,
CategoryID: 0
}
]);
console.log(payments);
setUpdated(!updated);
}
const save = () => {
alert('Save BTN');
}
const render = () => {
if(loading) {
return (
<RctCollapsibleCard
colClasses="col-xs-12 col-sm-12 col-md-12"
heading={"Loading Allocate Payment..."}
>
<LinearProgress />
</RctCollapsibleCard>
);
} else {
const showSaveBTN = () => {
if(showSave) {
return (
<>
<Button type="button" color="primary" onClick={save}>Save</Button>
{' '}
<Button color="warning" onClick={() => props.setOpenAllocate(false)}>Cancel</Button>
</>
);
} else {
return <Button color="warning" onClick={() => props.setOpenAllocate(false)}>Cancel</Button>;
}
}
const heading = `Allocating ${tenantName} payment of ${<NumberFormat displayType={'text'} value={paymentAmount} thousandSeparator={true} prefix={'$'} />}`;
return (
<>
<div className="row">
<div className="col-sm-12 col-md-12 col-xl-12">
<RctCollapsibleCard heading={heading}>
<Form>
{payments.map((element, index) => {
//console.log(element);
//console.log(index);
return (
<div className="row">
<div className="col-sm-4">
<Label className="mr-sm-10">Payment Category</Label>
<Input type="select"
value={element.CategoryID} onChange={(e) => handleCategoryChange(e.target.value, index)}
>
<option value="0">Select</option>
{categories.map((obj) => {
return (
<option
key={obj.PaymentsCategoryID}
value={obj.PaymentsCategoryID}
>
{obj.Category}
</option>
);
})}
</Input>
</div>
<div className="col-sm-4">
<Label className="mr-sm-10">Amount</Label>
<NumberFormat value={parseFloat(element.PaymentAmount).toFixed(2)} thousandSeparator={true} prefix={'$'}
onChange={(e) => handleAmountChange(e.value, index)} className="form-group"
/>
</div>
<div className="col-sm-3">
<Button type="button" color="danger" size="sm" className="w-auto" style={{marginTop: '10px'}}
onClick={handleDelete(index)}
>
Delete
</Button>
</div>
</div>
);
})}
<div className="row">
<div className="col-sm-4">
<Label className="mr-sm-10">Payment Category</Label>
<Input type="select" onChange={(e) => handleCategoryChange(e.target.value, -1)}>
<option value="0">Select</option>
{categories.map((obj) => {
return (
<option
key={obj.PaymentsCategoryID}
value={obj.PaymentsCategoryID}
>
{obj.Category}
</option>
);
})}
</Input>
</div>
<div className="col-sm-4">
<Label className="mr-sm-10">Amount</Label>
<NumberFormat thousandSeparator={true} prefix={'$'} className="forms-group"
onChange={(e) => handleAmountChange(e.value, -1)}
/>
</div>
</div>
<div className="row">
<div className="col-sm-2" style={{marginTop: '10px'}}>
<Button type="button" className="btn" onClick={() => addPayment()}>Add a Payment</Button>
</div>
</div>
<div className="row">
<div className="col-sm-12" style={{marginTop: '10px'}}>
<p>
<span>Payment Total: <NumberFormat displayType={'text'} value={paymentAmount} thousandSeparator={true} prefix={'$'} /></span>
<br />
<span style={{color: 'red'}}>Allocated Amount: <NumberFormat displayType={'text'} value={currentTotal} thousandSeparator={true} prefix={'$'} /></span>
</p>
</div>
</div>
{showSaveBTN()}
</Form>
</RctCollapsibleCard>
</div>
</div>
</>
);
}
}
return render();
}
export default Test;
当用户单击“添加付款”按钮时,是否有更好(更合适)的方式来管理添加付款行(使用选择和输入)?
谢谢
答案 0 :(得分:1)
callback_query.message
永远不会超过一个元素的原因有两个:
payments
中,它在 addPayment
周围有一个闭包,因此当 payment
函数在其中定义时,它只引用 payment
状态的版本特定渲染。React 在内存中控制状态和更多内容,因此通过刷新页面,您已经失去了 React 的大部分优势。
这是一个示例(基于您的代码),展示了如何在不刷新的情况下处理数据。
addPayment
const { useState, useEffect, useMemo } = React;
const App = () => {
// This is the method to add a new payment to the array (it default the value to 0)
const addPayment = () => {
setPayments([
...payments,
{
PaymentAmount: 5,
CategoryID: 0,
},
]);
};
// The payments array is where I will keep the payment category ID and Amount
const [payments, setPayments] = useState([]);
// I have a useEffect to reload the page and do some operations based on the updated variable
useEffect(() => {
// Perform some effects based on the payments here
// If payments is in the dependency array, this function will be called with the latest payments every time it changes!
console.log(payments);
}, [payments]);
// Perform memoized calculation on payments
const totalPayment = useMemo(
() => payments.reduce((sum, current) => sum + current.PaymentAmount, 0),
[payments]
);
const categories = [];
// I have a Form where I render the payments
return (
<div>
<button onClick={addPayment}>Add</button>
<span>Current Total: {totalPayment}$</span>
<form>
{payments.map((element, index) => (
<div>
Payment #{index}: ${element.PaymentAmount}{" "}
</div>
))}
</form>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));