首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >无法在react组件中设置状态

无法在react组件中设置状态
EN

Stack Overflow用户
提问于 2019-07-13 03:46:07
回答 3查看 292关注 0票数 0

我有一个看起来像这样的react组件。我调用cleanUpInvoices方法来格式化我的数组对象(Invoices)中的日期。这工作得很好,没有任何问题。我尝试通过setState连接到dateCleanUpResult。我得到的只是"dateCleanUpResult is not defined“。我试了这么多东西,但都不管用。我无法设置状态。

这段代码有什么问题?

下面是完整的代码

代码语言:javascript
运行
复制
        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;
EN

回答 3

Stack Overflow用户

发布于 2019-07-13 04:09:41

这几乎是正确的,但令人欣慰的是,当您返回数组的时,它可能只是您在组件的state处初始化的空数组。

我们修复了将一个回调函数传递给setState方法,这个函数返回你想要的状态,更新后的状态,对吗?

该回调函数将在确保设置了新的state之后调用,并且,我们还返回setState函数,因为它是返回新状态的函数。

代码语言:javascript
运行
复制
  return this.setState({
    dateCleanUpResult: invoice
  }, () => this.state.dateCleanUpResult);

对于这个问题,ARTICLE是一个很好的解释。

票数 0
EN

Stack Overflow用户

发布于 2019-07-13 04:25:16

我创建了一个jsfiddle,显示您可以更新案例中的状态。http://jsfiddle.net/efp82rjg/3/

我认为你得到了一个问题,因为你假设cleanUpInvoices()将返回状态的更新值。但它不会,因为setState是异步的,即使值将被更新,但它不会向您显示更新后的值。如果您想在setState()之后访问更新后的值,那么可以使用在setState函数之后可用的回调。请阅读此处的文档:https://reactjs.org/docs/react-component.html#setstate

代码语言:javascript
运行
复制
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>
  );
}
票数 0
EN

Stack Overflow用户

发布于 2019-07-13 05:16:56

我假设您在searchForInvoicesByDateMethod中记录返回值cleanUpInvoices时收到的值为"undefined“。虽然这是setState异步特性的结果,但是实现setState回调不会解决这个问题(如果没有更多的回调,它只会让您访问该处理程序范围内的更新状态)。如果你想坚持你当前的实现,我会返回一个promise,并异步/等待返回的promise值。当调用cleanUpInvoices时,这将延迟searchForInvoicesByDates方法中代码的执行。

代码语言:javascript
运行
复制
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返回的全部内容作为筛选器的起点。如果是这种情况,您可以立即从cleanUpInvoices返回结果--不需要状态更新。当然,如果您需要发票子集用于进一步的引用或操作,则情况会有所不同。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57013235

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档