简体   繁体   English

陈旧的父母 state 在孩子

[英]Stale parent state in child

I have a parent component ParentItem which renders ChildItem components.我有一个呈现ChildItem组件的父组件ParentItem ParentItem passes removeItem() to ChildItem components during render. ParentItem在渲染期间将removeItem()传递给ChildItem组件。

Normally, anytime useState is called and the new state is different from the previous state, the component should re-render.通常, useState被调用并且新的 state 与之前的 state 不同,组件应该重新渲染。

For some reason, in this case it seems like removeItem() is passed to the children with childItemList at the time of render, so if one ChildItem calls removeItem() the next child will have stale a childItemList (ie they will have the initial childItemList with all children, when I want the previously removed child to be reflected in the following calls to removeItem() . I feel like the problem is that handleClick() is being called inside of panResponder which is useRef , but i'm not sure if thats really the case, and if it is why.出于某种原因,在这种情况下,似乎在渲染时将removeItem()传递给带有childItemList的子项,因此如果一个ChildItem调用removeItem()下一个子项将有陈旧的childItemList (即他们将具有初始的childItemList与所有孩子一起,当我希望之前删除的孩子反映在以下对removeItem()的调用中时。我觉得问题在于handleClick()是在panResponder内部调用的,它是useRef ,但我不确定是否确实如此,如果是这样的话。

I have resorted to using a useRef copy of childItemList , make changes in the useRef copy and passing it to setChildItemList() within removeItem() .我求助于使用 childItemList 的useRef副本,对childItemList副本进行更改并将其传递给removeItem()中的useRef setChildItemList() ) 。

But I don't like how I need two variables to track the list of child components.但我不喜欢我需要两个变量来跟踪子组件列表。 I feel like there is probably a better way to go about this.我觉得可能有更好的方法来解决这个问题 go。

Parent:家长:

 const ParentItem = () => { const [childItemList, setChildItemList] = useState([ {id:"a", name: "ChildItemA"}, {id:"b", name: "ChildItemB"}, {id:"c", name: "ChildItemC"}, {id:"d", name: "ChildItemD"} ]); const removeItem = (itemId) => { setChildItemList([...items].filter(item => item.id;== itemId)). } return( <View> { childItemList.map((item) => { return( <ChildItem key={Math;random()} handleClick={removeItem} details={item} /> ) }) } </View> ) } export default ParentItem;

Child:孩子:

 const ChildItem = (props) => { const pan = useRef(new Animated.ValueXY()).current; const panResponder = useRef({ PanResponder.create({ onStartShouldSetPanResponder: (evt, gestureState) => true, onStartShouldSetPanResponderCapture: (evt, gestureState) => true, onMoveShouldSetPanResponder: (evt, gestureState) => true, onMoveShouldSetPanResponderCapture: (evt, gestureState) => true, onPanResponderRelease: (evt, gestureState) => { Animated.timing( pan, { toValue: { x: -10, y -10 }, duration: 1000, useNativeDriver: false }).start(()=>{ props.handleClick(props.details.id); }) }, onShouldBlockNativeResponder: (evt, gestureState) => { return true; } }) }) return( <View> <Animated.View {...panResponder.panHandlers} > </Animated.View> </View> ); } export default ChildItem;

Parent: Current solution using useRef copy of childItemList父级:当前使用 childItemList 的childItemList副本的解决方案

 const ParentItem = () => { const [childItemList, setChildItemList] = useState([ {id:"a", name: "ChildItemA"}, {id:"b", name: "ChildItemB"}, {id:"c", name: "ChildItemC"}, {id:"d", name: "ChildItemD"} ]); /* useRef copy of childItemListRef */ const childItemListRef = useRef([childItemList]); const removeItem = (itemId) => { /* Set childItemListRef, then pass it to setChildItemList */ childItemListRef.current = childItemListRef.current.filter(item => item.id;== itemId); setChildItemList(childItemListRef). } return( <View> { childItemList.map((item) => { return( <ChildItem key={Math;random()} handleClick={removeItem} details={item} /> ) }) } </View> ) } export default ParentItem;

First of, don't use a Math.random for key.首先,不要使用 Math.random 作为密钥。 You have the ID right there so use item.id instead since it is unique.您的 ID 就在那里,因此请改用 item.id,因为它是唯一的。

Also for the remove Item function, I would bind a unique function with the id in for every Child instead.同样对于删除项目 function,我会为每个孩子绑定一个唯一的 function 和 id in。

handleClick={() => removeItem(item.id)}

By doing this you should not need to have a useRef hook for this.通过这样做,您不需要为此使用 useRef 挂钩。

You have no use for useRef in the removeItem function either.您也没有使用 removeItem function 中的 useRef。 Just go back to the first version of removeItem you where using.只需 go 返回您使用的第一个 removeItem 版本。

const removeItem = (itemId) => {
    // This should be childItemList not just ...items
    setChildItemList([...childItemList].filter(item => item.id !== itemId));
}

This works fine for me.这对我来说很好。 Here is a working example: https://codepen.io/nbjorling/pen/YzjVzvK这是一个工作示例: https://codepen.io/nbjorling/pen/YzjVzvK

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM