javascript - 无法使用 setState 在反应 js 中更新对象的特定属性
问题描述
我正在获取数据,并且我已映射数据以显示它。一切都很好,但是当我尝试更新获取的数据时(我已经存储在一个数组中,只想通过其他方式更改它,如下所述)不会更新。我已经给出了下面的数据,我只想更改当我单击按钮时分别为每个对象的“数量”属性但是每次我尝试使用扩展运算符并给出一个逗号并尝试在此处定义映射对象的“数量”属性时,它不会更新数量属性并替换整个数组。你能告诉我如何编写一个 onClick 函数来复制整个数组(使用扩展运算符)然后更新数量属性。(获取的数据存储在一个数组中)
0: {id: 11, ordered: true, quantity: 5, user: 1, item: {…}}
1: {id: 12, ordered: true, quantity: 1, user: 1, item: {…}}
2: {id: 14, ordered: true, quantity: 1, user: 1, item: {…}}
3: {id: 15, ordered: true, quantity: 4, user: 1, item: {…}}
4: {id: 17, ordered: true, quantity: 3, user: 1, item: {…}}
这是我正在获取的数据。(上图)
0:
id: 11
item: {id: 10, title: "Watch", image: "https://github.com/divanov11/django_ecommerce_mod5/blob/master/static/images/watch.jpg?raw=true", price: "$20"}
ordered: true
quantity: 5
user: 1
它是每个对象中的数据(上图)。我想保持一切不变,只是分别更改每个对象的数量属性。下面是我的代码。
import React, { useEffect, useState } from 'react';
let Cart = () => {
let [myItems, setMyItems] = useState([])
let fetchData = () => {
fetch('http://127.0.0.1:8000/api/get-order-item/' + sessionStorage.getItem('id'), {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer' + ' ' + sessionStorage.getItem('token')
}
}).then(
(response) => {
return response.json()
}
).then(
(data) => {
if (data) {
setMyItems(data)
}
})
}
useEffect(
() => {
fetchData()
console.log(myItems)
}, []
)
return (
<div>
{
myItems.map(
(value) => {
return (
<div className='row w-100 m-auto' >
<div className="card-deck container-fluid m-auto bg-light">
<div className="card bg-light mt-4 mb-2 " >
<img src={value.item.image} className="card-img-top" alt="..." />
<div className="card-body border-top ">
<div className='d-flex justify-content-between' >
<h4>{value.item.title}</h4>
<div className='d-flex flex-row-reverse' >
<svg onClick={ () => { setMyItems( (prevState) => { return [...prevState , {value : { quantity : prevState.quantity - 1 }} ] } ) } } id='add' xmlns="http://www.w3.org/2000/svg" width="28" height="23" fill="currentColor" class="bi bi-plus" viewBox="0 0 16 16" >
<path fill-rule="evenodd" d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" />
</svg>
<input defaultValue={value.quantity} className='w-25 h-75 text-center' />
<svg onClick={() => { console.log(myItems) }} xmlns="http://www.w3.org/2000/svg" width="32" height="25" fill="currentColor" class="bi bi-dash" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8z" />
</svg>
</div>
</div>
<h5>{value.item.price}</h5>
<div class="form-check d-flex justify-content-between">
<input type="checkbox" class="form-check-input" id="quantity" checked={value.ordered} />
<label class="form-check-label" for="exampleCheck1">Proceed this item to checkout</label>
<button type="button" class="btn btn-success ">Save changes</button>
</div>
</div>
</div>
</div>
</div >
)
}
)
}
</div >
)
}
export default Cart;
在映射对象的映射函数内部,我只想创建一个按钮来更改它们各自对象的数量属性
解决方案
尝试是:
setMyItems( (prevState) => { return [...prevState , {value : { quantity : prevState.quantity - 1 }} ] } ) } }
首先,这很难内联阅读,所以我会将其移至一个函数,以便您了解您正在使用的内容。
接下来,而不是...prevState
传播整个前一个数组并用 追加一个新的尾部{value : ...}
,而是通过索引或 id 找到您想要变异的项目(一种特定于应用程序的决策 - 可能 id 更好)并将数组分成三个件:
- 数组前面从 0 到
i
- 我们要更改数量的项目,
i
- 数组从后面
i + 1
到最后
这可以通过切片和扩展来构建一个新数组来完成:
const newArr = [...arr.slice(0, i), arr[i], ...arr.slice(i + 1)];
最后一步:操纵arr[i]
物体调整数量。看起来数量在顶层,所以:
{...arr[i], quantity: newQuantity}
综上所述,这是一个可应用于代码的最小可运行示例:
<script type="text/babel" defer>
const {useEffect, useState} = React;
const mockItems = [
{id: 11, quantity: 5, item: {title: "foo"}},
{id: 12, quantity: 1, item: {title: "bar"}},
{id: 14, quantity: 1, item: {title: "baz"}},
{id: 15, quantity: 4, item: {title: "quux"}},
{id: 17, quantity: 3, item: {title: "corge"}},
];
fetch = () => new Promise((resolve, reject) =>
setTimeout(() =>
resolve({json: async () => mockItems})
, 1000)
);
const Cart = () => {
const [items, setItems] = useState([]);
useEffect(() => {
(async () => {
const response = await fetch("some endpoint");
setItems(await response.json());
})();
}, []);
const setQuantity = (id, quantity) => {
const i = items.findIndex(e => e.id === id);
setItems(prev => [
...prev.slice(0, i),
{...prev[i], quantity},
...prev.slice(i + 1),
]);
};
return (
<ul>
{!items.length ? "loading..." :
items.map(e =>
<li key={e.id}>
<div>{e.item.title}</div>
<div>
Qty: {e.quantity}
<button
onClick={() =>
setQuantity(e.id, e.quantity + 1)
}
>+</button>
<button
onClick={() =>
setQuantity(e.id, e.quantity - 1)
}
>-</button>
</div>
</li>
)
}
</ul>
);
};
ReactDOM.render(<Cart />, document.body);
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.0/umd/react-dom.production.min.js"></script>
推荐阅读
- multithreading - Python 的尝试 - 除了没有按预期工作
- java - for循环java中的计数器
- memory - 使用我的程序运行时,valgrind 给出非法操作码和错误指令错误
- javascript - 使用箭头函数将参数传递给回调函数
- c# - 在 XAML 中使用标记扩展作为属性 Setter 的值。{0} 对 Setter.Value 无效。唯一支持的 MarkupExtension 类型是
- postgresql - 如何添加具有递增整数值的列,但仅在另一列中的值更改时才递增
- ruby-on-rails - 尝试在我的应用程序上实现 post favouris
- php - php中的ajax发布方法
- swift3 - 如何使用故事板设置 uiview 的高度从 iphone 到 ipad 不同
- php - Ubuntu 16.04 PHP 7 PECL rar 无法运行