无法在React组件中设置状态

时间:2019-07-12 19:46:07

标签: reactjs

我有一个类似的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;

3 个答案:

答案 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返回结果-不需要状态更新。当然,如果您需要发票子集以作进一步参考或操作,则情况会有所不同。