我有一个类似的React组件。我调用方法cleanUpInvoices 在我的数组对象(发票)中格式化日期。无需任何操作,效果很好 问题。我试图将setState设置为dateCleanUpResult。 我得到的只是“未定义dateCleanUpResult”。我已经尝试了很多东西,但没有任何效果。 我无法设置状态。
此代码有什么问题?
这是完整的代码
class Tester extends PureComponent {
constructor(){
super();
this.state = {
invoices:[],
startDate:'',
endDate:'',
queryResult:[],
dateCleanUpResult:[]
};
this.searchForInvoicesByDates = this.searchForInvoicesByDates.bind(this);
this.handleChange = this.handleChange.bind(this);
this.cleanUpInvoices = this.cleanUpInvoices.bind(this);
}
handleChange({ target }) {
this.setState({
[target.name]: target.value
});
}
componentDidMount() {
const getCustomerId = this.props.customer.customerId;
AXIOS_AUTHED.get(`${API}/customers/${getCustomerId}/invoices?sort=settledDate,desc`)
.then(res => {
const invoices= res.data.content;
this.setState({ invoices });
})
}
cleanUpInvoices(){
const invoice = this.state.invoices;
invoice.forEach(function(invoicer) {
const newDate = invoicer.settledDate.substring(0, invoicer.settledDate.indexOf('T'));
invoicer.settledDate = moment(newDate, 'YYYY-MM-DD').format('MM-DD-YYYY');
});
return this.setState({
dateCleanUpResult: invoice
}, () => this.state.dateCleanUpResult);
}
searchForInvoicesByDates(startDate, endDate){
var myResult = this.cleanUpInvoices();
console.log(myResult);
//now perform your date search based on the result from above
let cleanedStartDate = moment(startDate).format('MM-DD-YYYY');
let cleanedEndDate = moment(endDate).format('MM-DD-YYYY');
let filteredResult = [];
for(let i = 0; i < this.state.dateCleanUpResult.length; i++){
if(this.state.dateCleanUpResult[i].settledDate >= cleanedStartDate && this.state.dateCleanUpResult[i].settledDate <= cleanedEndDate) {
filteredResult.push(this.state.dateCleanUpResult[i]);
}
}
console.log(filteredResult);
const listItems = filteredResult.map((number) =>
<li key={number.orderNumber}>{number.orderNumber} - {moment(number.settledDate).format('MMM-DD-YYYY')} </li>
);
this.setState({queryResult:listItems});
return (
<ul>{listItems}</ul>
);
}
render() {
return (
<PageBase
navigation={['Customer Solution', 'Tester App']}
>
<div className="row">
<div className="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<Paper>
<Typography className="customer-solution-subheader" component="h3" variant="subheading">
Tester App
</Typography>
<form>
<div className="customer-form-details">
<span>DATE RANGE COVERED*</span><br/>
<span className="ctrCalendar">
<label htmlFor="start">Start date:</label>
<input type="date" id="start" name="startDate" value={this.state.startDate} onChange={this.handleChange} required></input>
</span>
<span className="ctrCalendar">
<label htmlFor="start">End date:</label>
<input type="date" id="end" name="endDate" value={this.state.endDate} onChange={this.handleChange} required></input>
</span>
<span>
<Button variant="contained" className="next-button" id="btnSearchDates" onClick={() =>this.searchForInvoicesByDates(this.state.startDate, this.state.endDate)}>Search</Button><br/><br/>
</span>
<p>Search Result (Invoices/Dates)</p>
<div role="content" className="invContentParent">
<div name="teach" id="invContentChild">
</div>
</div>
</div>
</form>
</Paper>
</div>
</div>
</PageBase>
);
}
}
export default Tester;
答案 0 :(得分:0)
这几乎是正确的,但令人高兴的是,当您为数组返回时,它可能只是要在组件的state
处初始化的空数组。
我们修复了将回调函数传递给setState
方法的问题,该方法返回的状态是您想要的状态,是正确的吗?
在确保已设置新的state
之后,将调用该回调函数,并且我们还返回了setState
函数,因为它是一个返回新状态的函数。
return this.setState({
dateCleanUpResult: invoice
}, () => this.state.dateCleanUpResult);
ARTICLE是对此事的很好解释。
答案 1 :(得分:0)
我创建了一个jsfiddle,显示可以根据情况更新状态。 http://jsfiddle.net/efp82rjg/3/
我认为您遇到了问题,因为您假设cleanUpInvoices()将返回状态的更新值。但这不是因为setState是异步的,即使值将被更新,但也不会向您显示更新的值。如果要在setState()之后访问更新的值,请使用setState函数之后可用的回调。请在此处阅读文档:https://reactjs.org/docs/react-component.html#setstate
class Hello extends React.Component {
constructor() {
super();
this.state = {
invoices: [
{ settledDate: 'no' },
{ settledDate: 'no' },
],
dateCleanUpResult: [],
};
this.cleanUpInvoices = this.cleanUpInvoices.bind(this);
}
cleanUpInvoices() {
const invoice = this.state.invoices;
invoice.forEach((invoicer) => {
invoicer.settledDate = 'testing';
});
this.setState({
dateCleanUpResult: invoice,
});
return this.state.dateCleanUpResult;
}
render() {
return (
<div>
<button onClick={this.cleanUpInvoices}>test</button>
{this.state.dateCleanUpResult.map(item => (
<div>{item.settledDate}</div>
))}
</div>
);
}
答案 2 :(得分:0)
我假设您在“ searchForInvoicesByDateMethod”中记录返回值cleanUpInvoices的位置收到了“ undefined”值。尽管这是setState异步性质的结果,但实现setState回调不会解决此问题(仅此而已,它只会让您访问该处理程序范围内的更新状态)。如果您想坚持当前的实现,我将返回一个Promise,并异步/等待返回的Promise值。调用cleanUpInvoices时,这将延迟searchForInvoicesByDates方法中代码的执行。
cleanUpInvoices(){
// Avoid directly mutating state and generating circular reference by creating new array with map
const invoice = this.state.invoices.map(invoice => Object.assign({}, invoice));
//.....
//.....
return new Promise((res) => {
return this.setState({
dateCleanUpResult: invoice
}, () => res(this.state.dateCleanUpResult)));
}
}
////////
async searchForInvoicesByDates(startDate, endDate){
var myResult = await this.cleanUpInvoices();
//....
}
为不偏离提出的问题,这是另一个可以简化实现的快速思路。看起来您最初是在componentDidMount上进行API调用以检索发票的全部内容,然后根据用户输入按日期生成一个子集。是否有必要将生成的子集保持在状态中?每次按日期搜索发票时,似乎都希望使用从API返回的完整Universe作为过滤器的起点。如果是这种情况,您可以立即从cleanUpInvoices返回结果-不需要状态更新。当然,如果您需要发票子集以作进一步参考或操作,则情况会有所不同。