React钩子状态变量在重新渲染后不更新 [英] React hooks state variable not updating after rerender

查看:45
本文介绍了React钩子状态变量在重新渲染后不更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在以下示例中,我有一个要更新的元素(水果)数组,并使用更新后的数组执行其他操作(在此特定情况下保存更新后的列表).我的理解是重新渲染状态将更新......但它不会在这里......或者状态更新和我的操作之间存在延迟.

addFruit 函数中,我可以看到Peach"被立即添加,但 saveFruits 函数的控制台仍然显示状态 fruit 仍然存在不变.我怎样才能更新它以立即使用.(我知道在这种情况下我可以将 newFruits 变量传递给 saveFruits 进行更新,但我也需要为其他地方更新 fruits ).

请原谅我,因为这是我关于反应异步状态的第 100 万个问题,但有些东西还没有为我点击.

const { useState } = React;函数 ParentComp() {const[fruits, setFruits] = useState(['Apple', 'Orange', 'Banana', 'Pomegranate', 'Kiwi'])const addFruit = () =>{让 newFruits = Object.assign([],fruits)newFruits.push('桃子')setFruits(新水果)保存水果()}const saveFruits = () =>{console.log('保存水果的 API 请求.', 水果)}返回 (<div>{fruit.map((fruit, key) => <div key={key}>{fruit}</div>) }<button type="button" onClick={addFruit}>添加桃子</button>

)}ReactDOM.render(, document.getElementById('root'))

<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin><<;/脚本><script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script><div id="root"></div>

解决方案

console.log fruits 不准确,因为对 fruits 的引用仍然指的是 fruits 您在调用 setFruits 之前拥有的.

如果我们console.log newFruits,其中有变化,它会更准确地了解正在发生的事情.

按照@Atul 的建议,useEffect 可能更好.

在旧的 React 类中可视化这是如何完成的有时会有所帮助.在旧的 React 类中,这相当于这个(在某种程度上不是实际上但足够接近来说明这一点)(阅读更多:https://reactjs.org/docs/hooks-state.html)

class ParentComp extends React.Component {构造函数(){极好的();this.state = {水果:['苹果','橙色','香蕉','石榴','猕猴桃']};}addFruit = () =>{让 newFruits = Object.assign([], this.state.fruits);newFruits.push('桃子')this.setFruits(newFruits)this.saveFruits();}setFruits = (水果) =>{this.setState({水果});}saveFruits = () =>{console.log(this.state.fruits);}使成为() {返回 (<div>{this.state.fruits.map((fruit, key) => {return (<div key={key}>{fruit}</div>) })}<button type="button" onClick={this.addFruit}>添加桃子</button>

);}}ReactDOM.render( , document.getElementById('root'))

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script><div id="root"></div>

我们在上面遇到了同样的问题,但它可能会更清楚一些.fruits 的 setState 确实被调用,但是 console.log 发生在状态/渲染更改发生之前,所以 this.state.fruits 仍然指的是之前的状态.

我强烈推荐阅读React hooks: not magic,只是数组 以更好地了解钩子幕后发生的事情.它有助于解释很多.

In the following example I have an array of element (fruits) that I want to update and use the updated array to perform other operations (in this specific case saving the updated list). My understanding was on re rerender the state will update...but it does not here..or there is a delay between state updating and my action.

In the addFruit function I can see 'Peach' being immediately added but the console from the saveFruits function still shows the state fruit remains unchanged. How can I have this updated to use immediately. (And I know in this case I can pass newFruits variable to saveFruits to update but I need fruits to be updated for other places as well).

Forgive me because this is my millionth question about react async states but there's something just not clicking for me yet.

const { useState } = React;

function ParentComp() {
    const[fruits, setFruits] = useState(['Apple', 'Orange', 'Banana', 'Pomegranate', 'Kiwi'])


   const addFruit = () => {
      let newFruits = Object.assign([], fruits)
      newFruits.push('Peach')
      setFruits(newFruits)
      saveFruits()
   }
   
   const saveFruits = () => {
      console.log('API req to save fruits.', fruits)
   }

   return (
    <div>
    { fruits.map( (fruit, key) => <div key={key}>{fruit}</div> ) }
      <button type="button" onClick={addFruit}>Add Peach</button>
    </div>
   )
}

ReactDOM.render(<ParentComp />, document.getElementById('root'))

<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>

<div id="root"></div>

解决方案

It's not accurate to console.log fruits because the reference to fruits is still referring to the fruits you had before you called setFruits.

If we console.log newFruits, which has the change, it would be more accurate of what is happening.

EDIT: It's probably better to useEffect as what @Atul suggested though.

It sometimes helps to visualize how this is done in old React classes. In old React classes the equivalent of this is this (to some degree not actually but close enough to illustrate the point) (Read more: https://reactjs.org/docs/hooks-state.html)

class ParentComp extends React.Component {
  constructor() {
    super();
    this.state = {
      fruits: ['Apple', 'Orange', 'Banana', 'Pomegranate', 'Kiwi']
    };
  }

  addFruit = () => {
    let newFruits = Object.assign([], this.state.fruits);
    newFruits.push('Peach')
    this.setFruits(newFruits)
    this.saveFruits();
  }

  setFruits = (fruits) => {
    this.setState({
      fruits
    });
  }

  saveFruits = () => {
    console.log(this.state.fruits);
  }

  render() {
    return ( 
        <div> 
         {this.state.fruits.map((fruit, key) => {
          return (<div key={key}>{fruit}</div>) })} 
          <button type="button" onClick={this.addFruit}>Add Peach</button>
        </div>
    );
  }
}
ReactDOM.render(<ParentComp /> , document.getElementById('root'))

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>

We get the same problem above but it might be a little clearer. The setState for fruits does get called but the console.log happens before the state/render change happens so this.state.fruits is still referring to what was in the state before.

I highly recommend reading React hooks: not magic, just arrays to get a better sense of what goes on behind the scenes of hooks. It helps explain it a lot.

这篇关于React钩子状态变量在重新渲染后不更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆