使用 array.map 后 React Native 重新渲染 UI

React Native rerendering UI after using array.map

我正在尝试让图标在单击时切换其视觉效果(如复选框)。通常在本机反应中我会做这样的事情:

const [checkbox, setCheckbox] = React.useState(false);
...
<TouchableHighlight underlayColor="transparent" onPress={() => {setCheckbox(!setCheckbox)}}> 
    {added ? <MaterialIcons  name="playlist-add-check" size={40} />
    : <MaterialIcons  name="playlist-add" size={40} />}
</TouchableHighlight>

不过我做了一些更改,现在我似乎无法复制这种行为。我正在使用 AsyncStorage class 来存储和获取要显示的对象数组。为了简化,在下面的示例中我删除了存储代码,每个对象都有一个 'id' 和一个 'added' 属性,它本质上是复选框的布尔值。

我现在正在尝试更新每次按下时向用户显示的图标。我知道正在调用该函数,但它不会更新图标。我正在使用 array.map 创建图标列表。我在这里创建了一个演示,代码如下:https://snack.expo.dev/@figbar/array-map-icon-update

const templateObject = {
  id: 0,
  added: false,
};
const templateObject2 = {
  id: 1,
  added: true,
};
export default function App() {
  const [savedNumbers, setSavedNumbers] = React.useState([]);

  React.useEffect(() => {
    setSavedNumbers([templateObject,templateObject2]);
  }, []);

  const populateSavedNumbers = () =>
    savedNumbers.map((num, index) => <View key={index}>{renderPanel(num.id,num.added)}</View>);
  const updateNumber = (id) => {
    let capturedIndex = -1;
    for(var i = 0; i < savedNumbers.length; i += 1) {
        if(savedNumbers[i].id === id) {
          capturedIndex = i;
          break;
        }
    }
    let _tempArray = savedNumbers;
    _tempArray[capturedIndex].added = !_tempArray[capturedIndex].added;
    setSavedNumbers(_tempArray);
  }
  const renderPanel = (id:number, added:boolean) => {
    return (
        <View>
          <TouchableHighlight underlayColor="transparent" onPress={() => {updateNumber(id);}}> 
              {added ? <MaterialIcons  name="playlist-add-check" size={40} />
              : <MaterialIcons  name="playlist-add" size={40} />}
           </TouchableHighlight>
        </View>
    );
  }
  return (
    <View>
    <View>buttons:</View>
      <View>{populateSavedNumbers()}</View>
    </View>
  );
}

这是一个常见的 React 陷阱,当事情看起来应该重新渲染时却没有重新渲染。 React 对新旧状态进行浅层比较,以决定是否触发重新渲染。这意味着,当将变量声明为简单地等于对象或数组的状态变量时,不会触发重新渲染,因为这两个变量现在引用相同的底层数据结构。

在这种情况下,您将 _tempArray 设置为引用数组 savedNumbers 而不是创建新数组。因此,React 的浅比较返回为“相等”,并且认为没有必要重新渲染。

要解决此问题,请更改此行:

let _tempArray = savedNumbers;

对此:

let _tempArray = [...savedNumbers];