更新父状态时更新子组件
Posted
技术标签:
【中文标题】更新父状态时更新子组件【英文标题】:Update child component when parent state is updated 【发布时间】:2021-03-02 13:44:13 【问题描述】:当我的父组件中有新的更新时,发生在 function updateItemValue()
中,items
状态只会在父组件中更新。子组件不会在实例中更新。仅当updateItemValue()
被触发两次时才会更新。
有点像:
第一轮,家长更新项目,孩子没有收到更新。 第二轮,家长更新项目,孩子只收到第一轮的更新父组件
const SelectItem = () =>
const items = useSelector(state => state.itemsReducer);
const [ itemUpdate, setItemUpdate ] = useState(false);
const [ group_id, setGroupId ] = useState(false);
useEffect(() =>
updateItemValue()
, [itemUpdate])
function updateItemValue()
// original items value
/*
[
"_id":1, "name":"Item 1", "description":"Item 1 description",
"_id":2, "name":"Item 2", "description":"Item 2 description",
"_id":3, "name":"Item 3", "description":"Item 3 description"
]
*/
// step 3 : now this function get called because the group_id is updated
items.forEach((item, i) =>
if (group_id == item.group_id)
// step 4 : update the value of items state, add extra data, once this updated, I expect the new items value to be passed to child component
items[i].extra = true;
);
// step 2 : update the group_id and set the itemUpdate to true to trigger useEffect
function selectGroup(group_id)
setItemUpdate(true)
setGroupId(group_id)
return(
<div>
/* step 1: select option */
<button onClick=() => selectGroup(1)>Option 1</button>
<button onClick=() => selectGroup(2)>Option 2</button>
items.map((item) => (
<ItemCard
key=item._id
id=item._id
name=item.name
description=item.description
onClick=(value) => updateSelectedItem(value)
/>
))
</div>
)
子组件
export default function ItemCard(id, name, description, onClick, extra)
console.log(extra) // the value is undefined when selectGroup() 1st triggered from parent
return (
<div onClick=() => onClick(id)>
<div>
<p>name</p>
<p>description</p>
extra ? '<p>Extra item is required</p>' : null
</div>
</div>
)
p/s : 状态 items
来自 redux 状态。所以updateItemValue()
的状态更新是添加一些我想在子组件中使用的额外值。
【问题讨论】:
您能否更新问题以包含更多Minimal, Complete, and Reproducible 组件代码示例? “子组件”不是有效的反应组件。我们是否假设“子组件”是ItemCard
? itemUpdate
是什么? updateSelectedItem
在哪里定义?什么叫updateItemValue
?
我已经更新了我的代码。
我不知道items
是什么,但是您正在对其进行变异,因此父组件可能会看到相同的对象引用,因此不知道要重新渲染。你能分享一下items
是什么,在哪里定义的吗?
@DrewReese 对此感到抱歉。我忘了包括它。请再次检查最新更新。谢谢!
【参考方案1】:
问题
你正在改变一个对象引用
function updateItemValue()
items.forEach((item, i) =>
if (group_id == item.group_id)
items[i].extra = true; // <-- state object mutation!
);
解决方案
看起来您正在使用 Redux,因为您使用的是 useSelector
react 钩子。
const items = useSelector(state => state.itemsReducer);
我假设您也可以访问 useDispatch
挂钩和操作来调度以更新您的状态。
您可能会稍微简化您的组件代码,并将更新逻辑移至 reducer,以便正确更新 stat。
const SelectItem = () =>
const items = useSelector((state) => state.itemsReducer);
const dispatch = useDispatch();
// step 2: dispatch action to update state via the group_id
function selectGroup(groupId)
dispatch( type: "UPDATE_GROUP", groupId );
return (
<div>
/* step 1: select option */
<button onClick=() => selectGroup(1)>Option 1</button>
<button onClick=() => selectGroup(2)>Option 2</button>
items.map((item) => (
<ItemCard
key=item._id
id=item._id
name=item.name
description=item.description
onClick=(value) => updateSelectedItem(value)
/>
))
</div>
);
;
我现在只是猜测一下reducer函数,它可能类似于以下。
const initialState =
items: [],
const itemsReducer = (state = initialState, action) =>
switch (action.type)
...
// step 3: update items array by matching item group id
case "UPDATE_GROUP":
return
...state,
items: state.items.map((item) =>
item.group_id === action.groupId
?
...item,
extra: true
: item
)
;
...
default:
return state;
;
补充建议
您还可以稍微简化子组件ItemCard
。直接附加点击处理程序并简化条件渲染。另外,我不知道这是否是故意的(我认为不是),但您可能不希望字符串文字 "<p>Extra item is required</p>"
呈现。
function ItemCard( name, description, onClick, extra )
return (
<div onClick=onClick>
<div>
<p>name</p>
<p>description</p>
extra && <p>Extra item is required</p>
</div>
</div>
);
并更新父级中的映射。不要传递 id
属性,而是将 item._id
传递给 updateSelectedItem
回调。
items.map((item) => (
<ItemCard
key=item._id
name=item.name
description=item.description
onClick=() => updateSelectedItem(item._id)
/>
))
【讨论】:
感谢您的详细解释:)以上是关于更新父状态时更新子组件的主要内容,如果未能解决你的问题,请参考以下文章
防止子级在更新父级状态时重新渲染,使用父级方法作为本机反应的道具