首页 > 解决方案 > 影响元素条件显示的异步状态

问题描述

我有一个 FlatList 所在的屏幕(父级)renderItem ,并且显示了一个 Child 元素。

在这个 Child 元素中,我有一个Pressable,当用户单击它时,它会显示一个 Checked Icon 并更改其背景颜色。

这基于中的状态数组动态发生,在每个子中我传递状态数组。renderItem

在 Child 组件中,我检查此 Child 元素的 ID 是否存在,如果存在,则会显示一个 Checked Icon 并且背景会改变颜色。

我知道states在 React 中是异步的,但我总是在处理这些场景时遇到问题。

我已经尝试检查驻留的父屏幕FlatList,而不是将布尔道具传递给孩子是否显示选中的图标。

例如(抱歉,在 SO 中格式化代码时总是遇到问题)

      <FlatList
        data={displayData}
        renderItem={({item}) => (
          <Child              
            key={item} 
            userData={item}
            id={item}
            isSelected={selectedIds?.includes(item)}
            // selectedIds={selectedIds}
            selectedHandler={id => selectedHandler(id)} 
          />
        )}
        keyExtractor={item => item} 
      />

代替

// In Parent Screen

<FlatList
        data={displayData}
        renderItem={({item}) => (
          <Child              
            key={item} 
            userData={item}
            id={item}
            selectedIds={selectedIds} // here
            selectedHandler={id => selectedHandler(id)} 
          />
        )}
        keyExtractor={item => item} 
      />

// In Child element
const Child = ({
  id,
  selectedIds,
  selectedHandler
}) => {
  return (
        <Pressable
          style={[
            styles.checkContainer,
            selectedIds?.includes(id) && { backgroundColor: '#3D9A12' }
          ]}
          onPress={onPressHandler}
        >
          {selectedIds?.includes(id) && <CheckIcon />} {/* Problem lies here. Not showing Checked Icon */}
        </Pressable>
  );
};

我不会在这里转储任何代码,因为我已经对我的问题的重现做了一些小吃

我很感激任何帮助。非常感谢

未选中:

未经检查

检查:

已检查

标签: javascriptreactjsreact-nativestate

解决方案


问题出在 selectedHandler 函数中。

您将状态的引用存储在此变量中。

let selectedArr = selectedIds;

然后通过这样做直接修改状态本身:

selectedArr.push(id);

这就是为什么状态更新不会触发组件的重新渲染。

相反,您需要做的是:

let selectedArr = [...selectedIds];

通过传播它,您将存储数组的副本而不是对其的引用。现在,如果您修改 selectedArr,您将不会修改您的状态。

我对您提供的零食进行了更改,现在效果很好。更新的 selectedHandler 函数:

const selectedHandler = id => {
    let selectedArr = [...selectedIds];

    console.log('before selectedArr', selectedArr);

    if (selectedArr.includes(id)) {
      selectedArr = selectedArr.filter(userId => userId !== id);
      setSelectedIds(selectedArr);

      console.log('after selectedArr', selectedArr);
      return;
    }

    if (selectedArr.length > 2) {
      selectedArr.shift();
    }

    selectedArr.push(id);

    console.log('after selectedArr', selectedArr);
    setSelectedIds(selectedArr);
  };

推荐阅读