【问题标题】:setState inside for loop doesn't update state correctlyfor 循环内的 setState 无法正确更新状态
【发布时间】:2021-03-06 19:03:25
【问题描述】:

我有 3 个 div。当我单击特定按钮时,每个人都会激活课程。他们中的每个 div 都有一个状态变量,只要它是真的我将 className='active' 添加到连接到它的 div 中:

当我点击按钮时,状态发生变化,但 div 没有激活类

async activeLang(e) {

  let lang = e.target.getAttribute('lang');

  for (const key in this.state.status) {

    if (key === lang) {
      await this.setState(state => {
        state.status[key] = true
      })
    }else{
      await this.setState(state => {
        state.status[key] = false
      })
    }
  
  }

  console.log(this.state.status);
}

当我将功能更改为此它可以工作:

   activeLang(e) {
    let lang = e.target.getAttribute('lang');

    this.setState({
      status:{
       en: false,
       ar: false,
       fr: false,
      }
    })

    this.setState(state => {
      state.status[lang] = true
    })

    console.log(this.state.status);
  }

================================================ =

<ul>
 <li lang="en" onClick={this.activeLang} className={this.state.status.en ? 'active' : '' }>EN</li>
 <li lang="ar" onClick={this.activeLang} className={this.state.status.ar ? 'active' : ''}>AR</li>
 <li lang="fr" onClick={this.activeLang} className={this.state.status.fr ? 'active' : ''}>FR</li>
</ul>

================================================ =

<div className={this.state.status.en ? 'to-input en active' : 'to-input en'}>
 <input required type='text' onKeyUp={this.onInputChange} />
 <label title='Category name' placeholder='Ex. Business Cards'></label>
</div>

<div className={this.state.status.ar ? 'to-input ar active' : 'to-input ar'}>
 <input required type='text' onKeyUp={this.onInputChange} />
 <label title='اسم الفئة' placeholder='مثال: كروت العمل'></label>
</div>

<div className={this.state.status.fr ? 'to-input fr active' : 'to-input fr'}>
 <input required type='text' onKeyUp={this.onInputChange} />
 <label title='Nom de catégorie' placeholder='Ex. Cartes de visite'></label>
</div>

【问题讨论】:

  • 您不能在循环中使用 setState。 setState 不是 即时的,它会获取计划,并且 - 这是重要的部分 - 只有 last setState 在状态更新实际运行时“获胜”。所以永远不要在循环中使用 setState 。进行数据转换和所有其他工作,然后只使用新状态调用 setState once。这就是 setState 的意义所在:它将您的组件从之前的状态更新到新的状态。不要将其用于任何中介。

标签: javascript reactjs web


【解决方案1】:

不要循环执行。只需调用一次:

const lang = e.target.getAttribute('lang');
this.setState(state => ({
   ...state,
   status: Object.keys(state.status).reduce((acc,key) => ({
     ...acc,
     [key]:state.status[key] === lang // set all statuses to false except for `lang`
   }),{});
});

编辑:

此外,setState 不返回承诺,您不能 await 它。它确实接受回调,但这不是最好的解决方案(见上文)。

你不应该在循环中调用setState,否则会发生混乱的事情。

编辑#2:

从外观上看,我为您的状态找到了更好的解决方案。一次只能有一个语言处于活动状态,因此您不需要status - 您只需要知道激活的语言是什么,因此:

const state = { activatedLang: 'en' } // or 'fr' or 'ar'

那么你可以这样做:

this.setState({ activatedLang: e.target.getAttribute('lang') });

【讨论】:

  • 你的回答真的很好。我不知道 3 点运算符,我只是搜索它,它会有很大帮助。谢谢。
猜你喜欢
  • 2019-09-28
  • 1970-01-01
  • 2019-03-28
  • 1970-01-01
  • 1970-01-01
  • 2020-08-03
  • 1970-01-01
  • 2021-06-05
  • 2016-10-10
相关资源
最近更新 更多