【问题标题】:Stale parent state in child孩子中陈旧的父母状态
【发布时间】:2023-01-10 09:22:00
【问题描述】:

我有一个父组件 ParentItem 呈现 ChildItem 组件。 ParentItem 在渲染期间将 removeItem() 传递给 ChildItem 组件。

我知道这里的问题是removeItem()在渲染时被传递给带有childItemList的孩子,所以如果一个ChildItem调用removeItem(),下一个孩子将有陈旧的childItemList(即他们将有最初的childItemList 与所有孩子,当我希望之前删除的孩子反映在以下对 removeItem() 的调用中时。

我求助于使用 childItemList 的 useRef 副本,在 useRef 副本中进行更改并将其传递给 removeItem() 中的 setChildItemList()。但我不喜欢我需要两个变量来跟踪子组件列表。我觉得可能有更好的方法来解决这个问题。

家长:

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}
            />
          )
        })
      }
    </View>
  )
  
}
export default ParentItem;

孩子:

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;

父级:当前使用 childItemList 的 useRef 副本的解决方案

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}
            />
          )
        })
      }
    </View>
  )
  
}
export default ParentItem;

【问题讨论】:

    标签: reactjs react-native


    【解决方案1】:

    首先,不要使用 Math.random 作为密钥。您的 ID 就在那里,因此请改用 item.id,因为它是唯一的。

    同样对于 remove Item 函数,我会为每个 Child 绑定一个带有 id in 的唯一函数。

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

    通过这样做,您不需要为此使用 useRef 挂钩。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-20
      • 2015-06-14
      • 1970-01-01
      • 1970-01-01
      • 2019-05-07
      相关资源
      最近更新 更多