子组件无法通过父组件中的状态更新正确更新
Child component doesn't update correctly with state update in parent component
只是我有一个列表项,其中包含一个名称列表,单击任何列表项都会更改该项目的颜色,这是我的逻辑:
const App = () => {
const items = [
{
name: 'peter',
id: 1
},
{
name: 'Mark',
id: 2
},
{
name: 'john',
id: 3
}
]
const [id, setId] = useState(null);
const [names, setNames] = useState(items)
const setClickedItemId = (id) => {
setId(id)
}
const turnItemRed = () => {
setNames(prev => prev.map(i => i.id === id ? {...i, color: 'red' } : i))
}
return (
<div className="app">
<ul className="items">
{
names.map(i => {
return (
<Item
item={i}
setClickedItemId={setClickedItemId}
turnItemRed={turnItemRed}
/>
)
})
}
</ul>
</div>
)
}
function Item({item, ...props}) {
const { name, id} = item;
const { setClickedItemId, turnItemRed } = props;
return (
<li
className={`${item.color === 'red' ? 'red' : ''}`}
onClick={() => {
setClickedItemId(id);
turnItemRed()
}}
>{name}</li>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
这会呈现一个项目列表,我需要点击两次才能让一个项目变成红色,这意味着子组件没有捕捉到最新版本的状态,但是:
只是在父组件中的return语句之前添加那行代码,
const showingItems = names.map(i => i.id === id ? {...i, color: 'red'} : i)
然后使用该变量 showingItems
来呈现列表而不是状态变量 names
使其正确 并且不知道为什么
那么,为什么子组件 Items
没有获得最新版本的状态,而将状态存储在变量中使其起作用??
状态更新是批处理的,您的 onClick 会触发 2 个执行状态更新的函数。由于异步行为,第二个函数没有收到更新的值。
只需将 id 传递给 turnItemRed
函数,而不是从状态中获取它。
应用程序
const turnItemRed = (id) => { //<----take the id
setNames(prev => prev.map(i => i.id === id ? {...i, color: 'red' } : i))
}
项目
function Item({item, ...props}) {
const { name, id} = item;
const { setClickedItemId, turnItemRed } = props;
return (
<li
className={`${item.color === 'red' ? 'red' : ''}`}
onClick={() => {
setClickedItemId(id);
turnItemRed(id) //<---- pass the id
}}
>{name}</li>
)
}
编辑
上述问题的快速演示和修复是 here in the demo. 。只是添加这个,以便将来可能对其他读者有所帮助。
import React,{useState} from 'react';
export default () => {
const items = [
{
name: 'peter',
id: 1
},
{
name: 'Mark',
id: 2
},
{
name: 'john',
id: 3
}
]
const [id, setId] = useState(null);
const [names, setNames] = useState(items)
const setClickedItemId = (id) => {
setId(id);
turnItemRed(id);
}
const turnItemRed = (id) => {
setNames(prev => prev.map(i => i.id === id ? { ...i, color: 'red' } : i))
}
return (
<div className="app">
<ul className="items">
{
names.map(i => {
return (
<Item
item={i}
setClickedItemId={setClickedItemId}
turnItemRed={turnItemRed}
/>
)
})
}
</ul>
</div>
)
}
function Item({ item, ...props }) {
const { name, id } = item;
const { setClickedItemId, turnItemRed } = props;
return (
<li
style={{ color: item.color === 'red' ? 'red' : ''}}
onClick={() => {
setClickedItemId(id);
}}
>{name}</li>
)
}
只是我有一个列表项,其中包含一个名称列表,单击任何列表项都会更改该项目的颜色,这是我的逻辑:
const App = () => {
const items = [
{
name: 'peter',
id: 1
},
{
name: 'Mark',
id: 2
},
{
name: 'john',
id: 3
}
]
const [id, setId] = useState(null);
const [names, setNames] = useState(items)
const setClickedItemId = (id) => {
setId(id)
}
const turnItemRed = () => {
setNames(prev => prev.map(i => i.id === id ? {...i, color: 'red' } : i))
}
return (
<div className="app">
<ul className="items">
{
names.map(i => {
return (
<Item
item={i}
setClickedItemId={setClickedItemId}
turnItemRed={turnItemRed}
/>
)
})
}
</ul>
</div>
)
}
function Item({item, ...props}) {
const { name, id} = item;
const { setClickedItemId, turnItemRed } = props;
return (
<li
className={`${item.color === 'red' ? 'red' : ''}`}
onClick={() => {
setClickedItemId(id);
turnItemRed()
}}
>{name}</li>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
这会呈现一个项目列表,我需要点击两次才能让一个项目变成红色,这意味着子组件没有捕捉到最新版本的状态,但是:
只是在父组件中的return语句之前添加那行代码,
const showingItems = names.map(i => i.id === id ? {...i, color: 'red'} : i)
然后使用该变量 showingItems
来呈现列表而不是状态变量 names
使其正确 并且不知道为什么
那么,为什么子组件 Items
没有获得最新版本的状态,而将状态存储在变量中使其起作用??
状态更新是批处理的,您的 onClick 会触发 2 个执行状态更新的函数。由于异步行为,第二个函数没有收到更新的值。
只需将 id 传递给 turnItemRed
函数,而不是从状态中获取它。
应用程序
const turnItemRed = (id) => { //<----take the id
setNames(prev => prev.map(i => i.id === id ? {...i, color: 'red' } : i))
}
项目
function Item({item, ...props}) {
const { name, id} = item;
const { setClickedItemId, turnItemRed } = props;
return (
<li
className={`${item.color === 'red' ? 'red' : ''}`}
onClick={() => {
setClickedItemId(id);
turnItemRed(id) //<---- pass the id
}}
>{name}</li>
)
}
编辑 上述问题的快速演示和修复是 here in the demo. 。只是添加这个,以便将来可能对其他读者有所帮助。
import React,{useState} from 'react';
export default () => {
const items = [
{
name: 'peter',
id: 1
},
{
name: 'Mark',
id: 2
},
{
name: 'john',
id: 3
}
]
const [id, setId] = useState(null);
const [names, setNames] = useState(items)
const setClickedItemId = (id) => {
setId(id);
turnItemRed(id);
}
const turnItemRed = (id) => {
setNames(prev => prev.map(i => i.id === id ? { ...i, color: 'red' } : i))
}
return (
<div className="app">
<ul className="items">
{
names.map(i => {
return (
<Item
item={i}
setClickedItemId={setClickedItemId}
turnItemRed={turnItemRed}
/>
)
})
}
</ul>
</div>
)
}
function Item({ item, ...props }) {
const { name, id } = item;
const { setClickedItemId, turnItemRed } = props;
return (
<li
style={{ color: item.color === 'red' ? 'red' : ''}}
onClick={() => {
setClickedItemId(id);
}}
>{name}</li>
)
}