我刚刚开始 React,在这个项目列表教程中我有一些关于更新项目状态的问题。另外,我在 app.js 中使用功能组件 .So
const [items, setItems] = useState([
{
id: 1,
title: 'Banana',
bought: false
},
...
])
然后,我在 app.js 中有一个函数,可以在选中复选框时将购买更新为 true 或 false
// The id is passed in from Item.js down below
const markBought = (id) => {
setItems(
items.map(
item => {
if (item.id === id) {
/// If bought is false, checking it will make it true and vice versa
item.bought = !item.bought; // (1)
}
return item; // (2)
})
);
};
return (
<div className="App">
<Items items={items} markBought={markBought}></Items>
</div>
);
老师说我们正在使用一种叫做组件钻探的东西。所以在Items.js中,我们对每一项进行映射,将其一一显示出来,但我认为没有必要显示。
最终在 Item.js 中
<input type="checkbox" onChange={() => props.markBought(props.item.id)} />
{props.item.title}
该应用程序运行良好,但对我来说有点困惑。所以:
- 在app.js中,当我们更改购买状态后,我们是否还需要返回商品,就像条件为假时返回商品一样?为什么只有在错误时才返回该项目,而在正确时我们只更改它而不返回?
- 我读到map不会修改数组,所以markBought函数应该创建一个新的items数组,并且已经购买了修改过的东西,但是这个数组会发生什么,React如何知道将其“props”到item.js,而不是我硬编码的?
抱歉,如果这有点长,我们将非常感谢您的帮助。感谢您的阅读
最佳答案
您正在改变 map 中的一个项目,如果您将 Item 组件优化为纯组件,那么该组件将不会因为突变而重新渲染。请尝试以下操作:
//use useCallback so marBought doesn't change and cause
// needless DOM re renders
const markBought = useCallback(id => {
setItems((
items //pass callback to the setter from useState
) =>
items.map(
item =>
item.id === id
? { ...item, bought: !item.bought } //copy item with changed value
: item //not this item, just return the item
)
);
}, []);
这是一个完整的示例:
const { useCallback, useState, useRef, memo } = React;
function Items() {
const [items, setItems] = useState([
{
id: 1,
title: 'Banana',
bought: false,
},
{
id: 2,
title: 'Peach',
bought: false,
},
]);
const toggleBought = useCallback(id => {
setItems((
items //pass callback to the setter from useState
) =>
items.map(
item =>
item.id === id
? { ...item, bought: !item.bought } //copy item with changed value
: item //not this item, just return the item
)
);
}, []);
return (
<div>
{items.map(item => (
<Item
key={item.id}
item={item}
toggleBought={toggleBought}
/>
))}
</div>
);
}
//use memo to make Item a pure component
const Item = memo(function Item({ item, toggleBought }) {
const renderedRef = useRef(0);
renderedRef.current++;
return (
<div>
<div>{item.title}</div>
<div>bought: {item.bought ? 'yes' : 'no'}</div>
<button onClick={() => toggleBought(item.id)}>
toggle bought
</button>
<div>Rendered: {renderedRef.current} times</div>
</div>
);
});
//render the application
ReactDOM.render(<Items />, 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>
这是一个损坏的示例,其中您改变了项目,即使状态确实发生了变化,也看不到重新渲染:
const { useCallback, useState, useRef, memo } = React;
function Items() {
const [items, setItems] = useState([
{
id: 1,
title: 'Banana',
bought: false,
},
{
id: 2,
title: 'Peach',
bought: false,
},
]);
const toggleBought = useCallback(id => {
setItems((
items //pass callback to the setter from useState
) =>
items.map(
item =>
item.id === id
? ((item.bought = !item.bought),item) //mutate item
: item //not this item, just return the item
)
);
}, []);
return (
<div>
<div>
{items.map(item => (
<Item
key={item.id}
item={item}
toggleBought={toggleBought}
/>
))}
</div>
<div>{JSON.stringify(items)}</div>
</div>
);
}
//use memo to make Item a pure component
const Item = memo(function Item({ item, toggleBought }) {
const renderedRef = useRef(0);
renderedRef.current++;
return (
<div>
<div>{item.title}</div>
<div>bought: {item.bought ? 'yes' : 'no'}</div>
<button onClick={() => toggleBought(item.id)}>
toggle bought
</button>
<div>Rendered: {renderedRef.current} times</div>
</div>
);
});
//render the application
ReactDOM.render(<Items />, 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>
关于reactjs - useState 钩子(Hook)是否改变状态的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58893808/