当子项将更改分派到全局状态时如何防止重新渲染父项

时间:2021-07-14 16:15:09

标签: reactjs react-native

前提: 我有一个屏幕组件,一个手风琴组件,并且该组件具有子项组件。这些子项组件更改全局状态以处理其选中/未选中状态。

作为手风琴的兄弟,我有一个组件可以读取全局状态以显示检查计数,因此屏幕组件正在访问全局状态以将状态与检查计数组件显式调用分离< /p>

问题: 当手风琴子项调度更改为全局状态时,手风琴会重新渲染,从而与展开/折叠状态混淆。

发生这种情况是因为访问全局状态的屏幕组件正在重新渲染。由于我想继续从屏幕上分发这个全局状态,并避免显式访问组件内部的全局状态(努力使其可重用),我如何防止在子项更新时重新渲染屏幕全局状态,还要传播子项和检查计数组件的这些更改以重新呈现?

屏幕

export function List() {
  const{ state: { checkedItems }, dispatch } = useData()
  const [queue, setQueue] = useState([
      {id: '1'},
      {id: '2'},
      {id: '3'}
  ]);

  const setChecked = (id, shouldCheck) => {
    const type = shouldCheck ? 'checkItem' : 'uncheckItem'
    console.log('[ DISPATCH ] id:', id, 'type:', type)

    dispatch({type, payload: id})
  }

  return (
    <View>
      <Accordion>
        { 
          items
            .filter(item => item.type === 3)
            .map(item => useMemo(() => <AccordionSubItem item={item} onPress={setChecked}/>))
        }
      </Accordion>
        
      <CheckedCount indicator={checkedItems.length + ' selected'} visible={checkedItems.length > 0}>/        
    </View>
  )
};

AccordionSubItem

export default AccordionSubItem = ({ item, onPress}) => {
  const { state: {checkedItems} } = useData()

  return (
    <View style={styles.container}>
      <View style={styles.dataWrapper}>
        <Text style={styles.title}>{item.title}</Text>
        <Text style={styles.subtitle}>{item.subtitle}</Text>
      </View>
      <TouchableOpacity onPress={() => onPress(item.id, !checkedItems.includes(item.id))} style={styles.dataWrapper}>
      <Checkbox
        status={checkedItems.includes(item.id) ? 'checked' : 'unchecked'}
        color="white"
      />
      </TouchableOpacity>
    </View>
  );
};

注意:您看到的 dispatchstate 不是典型的 redux 设置。但最终状态还是由reducer返回,dispatch是一个异步函数

如何在防止屏幕重新渲染的同时确保子项组件和已检查计数组件更新其状态?

1 个答案:

答案 0 :(得分:1)

您的 List 组件在其内部状态改变时重新渲染完全没问题。这里的问题是您的 AccordionsubItem 没有键入。我相信键入它们应该可以解决问题:

<Accordion>
    {items
        .filter(item => item.type === 3)
        .map(item => <AccordionSubItem key={item.id} item={item} onPress={setChecked}/>)
    }
</Accordion>

我已经删除了这里的 useMemo,因为它看起来在这个地方没有任何优势。