我正在开发一个列表应用程序,但遇到组件未正确更新的问题。我从 JSON 文件中提取用户列表并将其保存在一个状态中。我正在使用上下文将该状态和其他信息传递给我的不同组件。最小的组件是分成可编辑列表的用户项目。这里列出了我遇到问题的项目列表。
例如,我有两个不同的 JSON 文件:
[{"userId": 81944,
"listId": 1,
"title": "testa",
"items": [
{
"listItemId": 0,
"product": "walnuts",
"quantity": 1,
"category": "Bakery",
"unit": "Each",
"cart": false
},
{
"listItemId": 1,
"product": "syrup",
"quantity": 1,
"category": "Beverages",
"unit": "Each",
"cart": true
},
{
"listItemId": 2,
"product": "cinnamon",
"quantity": 6,
"category": "Bakery",
"unit": "Each",
"cart": false
},
{
"listItemId": 3,
"product": "gabonzo beans",
"quantity": 1,
"category": "Canned Goods",
"unit": "Each",
"cart": true
},
{
"listItemId": 4,
"product": "diced tomatos",
"quantity": 7,
"category": "Produce",
"unit": "Each",
"cart": false
},
{
"listItemId": 5,
"product": "milk",
"quantity": 1,
"category": "Dairy",
"unit": "Oz",
"cart": false
},
{
"listItemId": 6,
"product": "salmon",
"quantity": 3,
"category": "Meat",
"unit": "Lb",
"cart": false
}]},{
"userId": 78863,
"listId": 4,
"title": "testd",
"items": [
{
"listItemId": 0,
"product": "half and half",
"quantity": 1,
"category": "Dairy",
"unit": "Each",
"cart": false
},
{
"listItemId": 1,
"product": "Blue Cheese",
"quantity": 1,
"category": "Dairy",
"unit": "Each",
"cart": false
},
{
"listItemId": 2,
"product": "Garlic",
"quantity": 1,
"category": "Produce",
"unit": "Each",
"cart": false
},
{
"listItemId": 3,
"product": "Chestnuts",
"quantity": 1,
"category": "Other",
"unit": "Each",
"cart": false
},
{
"listItemId": 4,
"product": "Balsamic Vinegar",
"quantity": 1,
"category": "Other",
"unit": "Each",
"cart": false
},
{
"listItemId": 5,
"product": "Onions",
"quantity": 1,
"category": "Produce",
"unit": "Each",
"cart": false
},
{
"listItemId": 6,
"product": "Flax Seed",
"quantity": 1,
"category": "others",
"unit": "Each",
"cart": false
},
{
"listItemId": 7,
"product": "Plantains",
"quantity": 1,
"category": "Produce",
"unit": "Each",
"cart": false
}]}]
在我的应用程序中,我有一个对话框,允许我在列表之间切换。然后,我获取列表并将其传递给要在屏幕上绘制的自定义组件。
import React, {useState,useEffect} from 'react';
const Card=(props)=>{
//console.log('prop');
const [cart, setCart] = useState(props.cart);
const [Product, setProduct] = useState(props.item);
const [Quantity, setQuantity] = useState(props.units);
// useEffect(()=>{
// setProduct(props.item)
// setQuantity(props.units)
// setCart(props.cart);
// },[])
console.log(props)
return (
<li key={props.value}>
<div>
<input type="checkbox" checked={cart} onChange={(e)=>{props.cartChange(e.target)}}/>
</div>
<div>
<input id={'product '+props.value} className='update'
type='text' value={Product}
onChange={(e)=>setProduct(e.target.value)}
/>
<br/>
<input id='quantityValue' className='update'
type='number' value={Quantity}
onChange={(e)=>setQuantity(e.target.value)}
/>
<span id='quantityType' className='update'>{props.unitType}</span>
</div>
<div>
<button id='save-button' type='button'
onClick={(e)=>{props.change(Product,Quantity,props.value)}}>✓ save</button>
<button id='delete-button' type='button'>✗ delete</button>
</div>
</li>
)
}
export default Card;
这是调用自定义组件的代码。您将看到我从 array.map() 调用它,这些数组很好,并且其中包含正确的信息。
import React, {useContext,useEffect} from 'react';
import {DataContext} from '../../../context/test/DataContext'
import Card from './ItemCard';
const update=(x)=>{
console.log(x)
}
const List = () =>{
const {listId} = useContext(DataContext);
const {userItemList} = useContext(DataContext);
const {GetItemList} = useContext(DataContext);
const {ListSplit} = useContext(DataContext);
const {foundList} = useContext(DataContext);
const {findList} = useContext(DataContext);
const {Updater} = useContext(DataContext);
const {cartUpdater} = useContext(DataContext);
useEffect(()=>{
GetItemList();
},[listId])
useEffect(()=>{
ListSplit();
},[userItemList])
// console.log(findList);
// console.log(foundList);
return(
<div>
<p>To find:</p>
<ul>
{findList.map((item,index)=><Card key={item.listItemId} index={index}
value={item.listItemId} cart={item.cart} item={item.product}
units={item.quantity} unitType={item.unit}
cartChange={cartUpdater} change={Updater} />)}
</ul>
<p>Found:</p>
<ul>
{foundList.map((item,index)=><Card key={item.listItemId} index={index}
value={item.listItemId} cart={item.cart} item={item.product}
units={item.quantity} unitType={item.unit}
cartChange={cartUpdater} change={Updater} />)}
</ul>
</div>
)
}
export default List;
每次我切换此选项时,我控制台注销的 Prop 都会正确更改。另外,如果我在开发工具(chrome)中查看我的组件,我会发现状态应该是正确的,但是我在屏幕上看到的内容不正确。例如,第二个项目是肉桂,如果我切换到第二个列表,则应该是蓝纹奶酪。 Prop 发生了变化,状态也发生了变化,但我在屏幕上看到的仍然是肉桂色。
我知道我可能没有解释清楚,但下面是我正在谈论的内容的屏幕截图。
最佳答案
您已接近注释掉的代码。由于您将 props 设置为 state(这是一个坏主意,我将在底部讨论),因此您的 useState
仅最初设置状态。您想要观看这些 Prop 并在它们更新时进行更新。
useEffect(() => {
setProduct(props.item)
setQuantity(props.units)
setCart(props.cart);
}, [props.item, props.units, props.cart]);
useEffect 会监视数组中的项目,以了解它是否应该触发。
顺便说一句 - 将 props 分配给 state 是一个坏主意,你已经知道为什么了 - 它们不会自动更新。您应该将这些 Prop 设置为父级的位置提升,并且可以将它们作为 Prop 传递下来并直接使用它们。您也可以将 setter 作为 props 传递下去,这可以更新父级。
This article ,而如果您愿意阅读的话,引用基于类的 React 组件可能会提供更多信息。
const { useState } = React;
const initialItems = [
{
listItemId: 1,
product: 'syrup',
quantity: 1,
category: 'Beverages',
unit: 'Each',
cart: true,
},
{
listItemId: 2,
product: 'cinnamon',
quantity: 6,
category: 'Bakery',
unit: 'Each',
cart: false,
},
{
listItemId: 3,
product: 'garbanzo beans',
quantity: 1,
category: 'Canned Goods',
unit: 'Each',
cart: true,
},
];
const Parent = () => {
const [items, setItems] = useState(initialItems);
const updateProduct = listItemId => (e) => {
setItems(items.map((item) => {
if (item.listItemId === listItemId) {
return { ...item, product: e.target.value };
}
return item;
}));
};
const updateQuantity = listItemId => (e) => {
setItems(items.map((item) => {
if (item.listItemId === listItemId) {
return { ...item, quantity: e.target.value };
}
return item;
}));
};
return (
<div>
<div style={{ width: "50%" }}>
All Items - (this state lives inside the parent component)
</div>
<div>
{items.map(item => (
<div>
<div>
Product - {item.product}
</div>
<div>
Quantity - {item.quantity}
</div>
</div>
))}
</div>
<div style={{ width: "50%" }}>
{items.map(item => (
<Child item={item} updateQuantity={updateQuantity} updateProduct={updateProduct} />
))}
</div>
</div>
);
};
const Child = ({ item, updateQuantity, updateProduct }) => {
return (
<div>
<div>
<span>
Product -
</span>
<span>
<input value={item.product} onChange={updateProduct(item.listItemId)} />
</span>
</div>
<div>
<span>
Quantity -
</span>
<span>
<input value={item.quantity} onChange={updateQuantity(item.listItemId)} />
</span>
</div>
</div>
);
};
ReactDOM.render(
<Parent />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
上面的一个小例子。父组件保存项目的状态并映射每个项目以创建子组件。这个例子的边缘有点粗糙。您可以执行一些操作,例如向每个输入添加 data-id
和 name
来简化更新功能,或者使用 useReducer
稍微提升该逻辑,但我认为它会让你朝着正确的方向前进。
关于javascript - ReactJS自定义组件输入值不随状态变化而更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59869125/