【问题标题】:How to prevent re-render of parent when child dispatches changes to global state当子级调度更改为全局状态时如何防止重新渲染父级
【发布时间】:2021-09-23 15:28:24
【问题描述】:

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

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

问题: 当手风琴子项将更改发送到全局状态时,手风琴会重新渲染,从而弄乱展开/折叠状态。

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

屏幕

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 设置。但归根结底,state 还是由 reducer 返回,dispatch 是一个异步函数

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

【问题讨论】:

    标签: reactjs react-native


    【解决方案1】:

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

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

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

    【讨论】:

    • 我正在处理的项目实际上导航组件的结构很差。他们正在创建导航组件,其中包含嵌套的屏幕,一团糟。一旦我修复它,它就解决了我的问题。但这仍然有效,我刚刚开始实施,还没有添加密钥。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-28
    • 2021-02-26
    • 2021-10-29
    • 2021-01-27
    • 1970-01-01
    • 2020-04-24
    • 1970-01-01
    相关资源
    最近更新 更多