【问题标题】:React array state update反应数组状态更新
【发布时间】:2021-10-22 02:34:39
【问题描述】:

我从数据库中得到一个书单并存储在一个状态变量中书单也有书价字段

const [books, setBooks]=useState([])
setBooks(data)

数组中的每个书籍对象都有 BookName、Author、Price、Discount 等属性

我已经渲染了一个如下的 html 表格

return ( <div>
{books.map((x,i) => ( <tr>
                         <td>x.bookName</td>
                         <td>x.price</td>
                         <td><MyCustomTextInput onChange={e => handleChange(e, x.id)}  value={x.discount}></MyCustomTextInput></td>
                      <tr></div>);

MyCustomTextInput 的示例代码如下

function MyCustomTextInput(props)
     { return (<div><TextInput></TextInput> </div>) 
     } exports default MyCustomTextInput

我更新“books”数组中相应对象价格的代码如下

function handleChange(x,id){
  var obj = books[id];
  obj.price = obj.price - e.target.value; //I am correctly getting discount in e.target.value
}

除了折扣后的价格没有反映在 UI 上之外,一切都正常工作。虽然它在数组中得到了正确更新,但没有反映在 UI 上。

任何帮助....

专家 -

【问题讨论】:

  • handleChange 函数根本不更新状态。你是不是忘了用新的状态给setBooks打电话?
  • @david 这是一个数组,我只是在更新已更改的相应书籍的价格。我不会再次重新分配数组。能否请您分享您对我如何做到这一点的想法?

标签: reactjs react-native


【解决方案1】:

你需要setBooks更新状态books

function handleChange(x, id) {
  setBooks(
    books.map((item) =>
      item.id === id ? { ...item, price: item.price - parseFloat(e.target.value) } : item,
    ),
  );
}

【讨论】:

  • 谢谢越南。感谢您的帮助。
【解决方案2】:

这是在设置一个值:

function handleChange(x, id){
  var obj = books[id];
  obj.price = obj.price - e.target.value;
}

但这不是更新状态。这里要遵循的主要规则是永远不要直接改变状态。在这里改变这条规则的结果是这个更新永远不会告诉 React 重新渲染组件。由于状态从未更新,因此在其他任何地方触发的任何重新渲染都会破坏您在此处更新的值。

您需要调用setBooks 来更新状态。例如:

function handleChange(x, id){
  setBooks(books.map(b =>
    b.id === id ? { ...b, price: b.price - parseFloat(e.target.value) } : b
  ));
}

这里本质上发生的是,您将现有数组置于状态并使用.map() 将其投影到新数组。在该投影中,您查找具有匹配 id 的记录并创建该记录的新版本,所有其他记录都按原样投影。然后将这个新数组(.map() 的结果)设置为新的更新状态。

当然还有其他方法可以构造新数组。您可以获取数组元素并按照现有方式对其进行更新,然后将其与.filter 的结果的扩展相结合以构建新数组。任何对您有意义的结构都可以正常工作。重点是您需要构造一个 new 数组并将其设置为新的状态值。

这将触发 React 重新渲染组件,并且新更新的状态将反映在渲染中。

【讨论】:

  • 谢谢大卫,我试图实现这个逻辑,但它实际上完全清除了书籍数组。当我使用“Amer Yousuf”提供的代码逻辑时,同样的事情发生了
  • @VR:你调试的时候,调用handleChange的时候,那个时候books的值是多少? (您可以在handleChange 中执行console.log(books) 并在浏览器的控制台上观察结果。)如果它是一个空数组,那么您的状态是一个空数组并且从未填充任何内容。您当前填充的问题中唯一的位置是:setBooks(data),但data 是什么?它来自哪里?
  • 我尝试调试,在值在数组中有条目之前。一旦代码进入 HandleChange 并执行上面提供的代码逻辑,它就会清除数组中的所有对象。一定是个问题.....
  • @VR:由于问题中的代码没有正确更新状态,您似乎有其他代码没有正确更新状态。此时的底线是,如果状态是一个空数组,那么你拥有的是一个空数组。这段代码不会“清除数组中的所有对象”,因为那里没有任何对象。除了上面问题中看到的内容之外,您很可能在代码的其他地方犯了错误。
  • 是的,这可能是正确的。但我真的很感激你向我解释的方式。我会找出空数组的原因。我会接受你的回答。您能否也让我知道这是否是下面提到的好方法? 1. 保留原始数组列表 2. 创建一个完整的重复列表(不参考原始) 3. 通过更新一个匹配条件的对象来修改重复列表 4. 使用 setBooks(modifiedList)
【解决方案3】:

为此,您需要在 handleChange 方法中更改价格后调用 setBooks 以重新渲染具有新更新状态的组件。

就像下面这样:

function handleChange(x,id){
  var obj = books[id];
  obj.price = obj.price - e.target.value; //I am correctly getting discount in e.target.value
  setBooks([...books]);
}

【讨论】:

  • 谢谢 Amer,但此代码逻辑正在清除我在 books 数组中的所有条目。
  • 我要检查的代码中一定还有其他一些逻辑问题。但是您提供的示例代码确实很有帮助。再次感谢您。
猜你喜欢
  • 2020-03-29
  • 2016-01-19
  • 1970-01-01
  • 2021-12-26
  • 2021-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多