【问题标题】:updating an array in React在 React 中更新数组
【发布时间】:2018-06-25 18:21:30
【问题描述】:

我有一个包含 16 个对象的数组,我在构造函数中声明为一个状态:

this.state = {
      todos:[...Array(16)].map((_, idx) => {
              return {active: false, idx}
            }), 
}

他们的状态将通过ComponentDidMount 中的 ajax 调用得到更新。

componentDidMount()
{
    var newTodos = this.state.todos;
    axios.get('my/url.html')
        .then(function(res)
        {
          newTodos.map((t)=>{
            if (something something)
            {
                t.active = true;
            }
            else
            {
                t.active = false; 
            }
          }
          this.setState({
            todos:newTodos,
          })
        }
}

最后,我渲染它:

render(){
   let todos = this.state.todos.map(t =>{
     if(t.active === true){
         console.log('true'}
     else{
         console.log('false')
     }
   }) 
   return (
     <div></div>
   )
}

它们在控制台中都显示为 active = false,它们从不进入 if 条件。什么时候 我打印出它似乎没有在渲染方法中更新的整个状态。在控制台中显示“下面的值刚刚更新”。

我认为更改ComponentWillMount 中的状态会再次调用渲染函数?
我如何让 React 接受 state 的新值?

【问题讨论】:

  • 您能对齐并修复您的componentWillMount 代码吗?乍一看,似乎 this.setState 调用是在 axios 调用之后调用的,但是您共享的代码既不是对齐属性,也不是所有块都关闭,所以很难说 setState 是否正在完成从您的then 块内部或直接从componentWillMount 内部。如果它来自 then 你要调用它,你要么必须使用箭头函数或保存 this 上下文,如果它来自 componentWillMount 那么你应该 await axios 调用并使 componentWillMount async
  • 对不起。我编辑了它
  • 然后map 返回一个新数组,它不会原地变异。最后,您的newTodos 仍然是您的旧this.state.todos。如果你没有在then回调中使用箭头函数,你仍然需要存储this上下文(哦,它仍然没有正确关闭,then函数错过了) ,但是对齐做了技巧)
  • 从未听说过[...Array(16)].map,很酷的把戏。对于那些不知道的人,Array(16).map 实际上并没有迭代任何项目,因为它们是空槽 stackoverflow.com/questions/27433075/…

标签: javascript ajax reactjs state


【解决方案1】:

那是因为你实际上并没有提供任何新的状态,而是改变它。

React 默认使用浅比较(如果对象引用相同的内存地址,则对象相等)。这正是这里发生的事情:

var newTodos = this.state.todos; // newTodos === this.state.todos

this.setState({  todos:newTodos }) // replaces two equal addresses, so it simply doesn't change anything

克隆你的 todos 数组是最简单的解决方案,虽然可能不是最高效的:

var newTodos = [...this.state.todos]; // newTodos !== this.state.todos

【讨论】:

  • 他没有改变任何地图返回一个新数组但它没有被分配
  • 因为数组的元素是对象,其中一些对象正在发生变异(属性 active 已更改)
  • 不仅地图没有分配给任何东西,地图的迭代器也没有返回任何东西。但会改变状态
  • 作者只是把它误认为是forEach
  • 没错,当人们使用map 而不是forEach 时,我总是觉得很困惑......我仍然认为他无法对响应做很多事情,但是这可能只是因为他的问题缺乏关于他想要做什么的数据(喜欢那些超级秘密做应用程序;))
【解决方案2】:
componentDidMount()
{
    var newTodos = [];    // <<<<<<<<<<<<<
    axios.get('my/url.html')
        .then(function(res)
        {
          newTodos = this.state.todos.map((t)=>{   //<<<<<<<<<<<<<<<
            if (something something)
            {
                t.active = true;
            }
            else
            {
                t.active = false; 
            }
            return t; //<<<<<<<<<<<<<<<<<<
          }     // <<<<< are you missing a semi-colon?
          this.setState({
            todos:newTodos,
          })
        }
}

map() 参数(在您的代码中)是一个函数,而不是一个表达式,因此必须提供明确的return。即:

xxx.map( t => ( "return t is implicit" ) );   
xxx.map( t => { "return t must be explicit" } );  

而且,正如@DanielKhoroshko 指出的那样,您的新变量指向 this.state。当然,永远,永远,永远不会直接改变 this.state。由于map() 返回一个新数组,而不是原始数组,这就是我们使用map() 而不是forEach() 的原因

【讨论】:

    猜你喜欢
    • 2018-11-22
    • 2019-07-13
    • 1970-01-01
    • 2021-08-31
    • 2019-05-06
    • 1970-01-01
    • 2021-10-18
    • 1970-01-01
    相关资源
    最近更新 更多