React Native:为什么 FlatList re-render 完全依赖于数据变化?
React Native: Why does FlatList re-render completely on data changes?
感谢阅读我的问题!几天以来我一直在努力解决这个问题:每次我对基础数据进行更改时,我的 Flatlist 组件 re-renders 列表中的所有项目。
情况:
- 我有一个 FlatList 组件渲染项目,其中包含一个 TouchableOpacity object 来切换这个项目的收藏状态。
- 如果按下此按钮,我希望我的 FlatList 中只有这个特定项目 change/re-render 而不是所有项目。感觉就像我通过调用 setListData 更新状态一样,它 re-renders 一切。
- 我在更复杂的设置中遇到过这个问题,但能够深入了解这个核心问题。或者这实际上是预期的行为?
代码:
import React, { useState } from "react";
import {
View,
Text,
StyleSheet,
FlatList,
TouchableOpacity,
} from "react-native";
const PlanerScreen = () => {
const [listData, setListData] = useState([
{ id: "1", name: "Banana", isFav: true },
{ id: "2", name: "Apple", isFav: false },
]);
const Item = ({ item, onPressHandler }) => {
console.log(item.name, " rendered");
const color = item.isFav ? "red" : "green";
return (
<View
style={{
flexDirection: "row",
width: "100%",
margin: 10,
}}
>
<Text>{item.name}</Text>
<TouchableOpacity
style={{ width: 100, height: 50, backgroundColor: color }}
onPress={onPressHandler}
/>
</View>
);
};
const favHandler = (id) => {
setListData(
listData.map((item) =>
item.id === id ? { ...item, isFav: !item.isFav } : item
)
);
};
console.log("FlatList rendered");
return (
<View style={{ flex: 1 }}>
<StatusBar style={selectedTheme === "light" ? "dark" : "light"} />
<FlatList
data={listData}
renderItem={({ item }) => (
<Item item={item} onPressHandler={() => favHandler(item.id)} />
)}
keyExtractor={(item) => item.id}
/>
</View>
);
};
export default PlanerScreen;
单击收藏夹切换按钮时的控制台输出:
FlatList rendered
Banana rendered
Apple rendered
FlatList rendered
Banana rendered
Apple rendered
FlatList rendered
Banana rendered
Apple rendered
您可以使用 React.memo 作为功能组件的 shouldComponentUpdate
的替代方法。
它告诉 React
何时 re-render 基于 prev 和 next 属性的组件。
import React, { useState, useCallback } from "react";
import {
View,
Text,
StyleSheet,
FlatList,
TouchableOpacity,
} from "react-native";
const styles = StyleSheet.create({
container: {
flex: 1,
}
})
const keyExtractor = (item) => item.id;
const Item = React.memo(({ item, onPressHandler }) => {
console.log(item.name, " rendered");
const color = item.isFav ? "red" : "green";
return (
<View
style={{
flexDirection: "row",
width: "100%",
margin: 10,
}}
>
<Text>{item.name}</Text>
<TouchableOpacity
style={{ width: 100, height: 50, backgroundColor: color }}
onPress={() => onPressHandler(item.id)}
/>
</View>
);
}, (prevProps, nextProps) => {
if (prevProps.item.isFav === nextProps.item.isFav) return true;
return false;
});
const PlanerScreen = () => {
const [listData, setListData] = useState([
{ id: "1", name: "Banana", isFav: true },
{ id: "2", name: "Apple", isFav: false },
]);
const favHandler = useCallback((id) => {
setListData(prevState => {
return prevState.map((item) =>
item.id === id ? { ...item, isFav: !item.isFav } : item
)
}
);
}, []);
console.log("### FlatList rendered #####");
return (
<View style={styles.container}>
<FlatList
data={listData}
renderItem={({ item }) => <Item item={item} onPressHandler={favHandler} />}
keyExtractor={keyExtractor}
/>
</View>
);
};
export default PlanerScreen;
感谢阅读我的问题!几天以来我一直在努力解决这个问题:每次我对基础数据进行更改时,我的 Flatlist 组件 re-renders 列表中的所有项目。
情况:
- 我有一个 FlatList 组件渲染项目,其中包含一个 TouchableOpacity object 来切换这个项目的收藏状态。
- 如果按下此按钮,我希望我的 FlatList 中只有这个特定项目 change/re-render 而不是所有项目。感觉就像我通过调用 setListData 更新状态一样,它 re-renders 一切。
- 我在更复杂的设置中遇到过这个问题,但能够深入了解这个核心问题。或者这实际上是预期的行为?
代码:
import React, { useState } from "react";
import {
View,
Text,
StyleSheet,
FlatList,
TouchableOpacity,
} from "react-native";
const PlanerScreen = () => {
const [listData, setListData] = useState([
{ id: "1", name: "Banana", isFav: true },
{ id: "2", name: "Apple", isFav: false },
]);
const Item = ({ item, onPressHandler }) => {
console.log(item.name, " rendered");
const color = item.isFav ? "red" : "green";
return (
<View
style={{
flexDirection: "row",
width: "100%",
margin: 10,
}}
>
<Text>{item.name}</Text>
<TouchableOpacity
style={{ width: 100, height: 50, backgroundColor: color }}
onPress={onPressHandler}
/>
</View>
);
};
const favHandler = (id) => {
setListData(
listData.map((item) =>
item.id === id ? { ...item, isFav: !item.isFav } : item
)
);
};
console.log("FlatList rendered");
return (
<View style={{ flex: 1 }}>
<StatusBar style={selectedTheme === "light" ? "dark" : "light"} />
<FlatList
data={listData}
renderItem={({ item }) => (
<Item item={item} onPressHandler={() => favHandler(item.id)} />
)}
keyExtractor={(item) => item.id}
/>
</View>
);
};
export default PlanerScreen;
单击收藏夹切换按钮时的控制台输出:
FlatList rendered
Banana rendered
Apple rendered
FlatList rendered
Banana rendered
Apple rendered
FlatList rendered
Banana rendered
Apple rendered
您可以使用 React.memo 作为功能组件的 shouldComponentUpdate
的替代方法。
它告诉 React
何时 re-render 基于 prev 和 next 属性的组件。
import React, { useState, useCallback } from "react";
import {
View,
Text,
StyleSheet,
FlatList,
TouchableOpacity,
} from "react-native";
const styles = StyleSheet.create({
container: {
flex: 1,
}
})
const keyExtractor = (item) => item.id;
const Item = React.memo(({ item, onPressHandler }) => {
console.log(item.name, " rendered");
const color = item.isFav ? "red" : "green";
return (
<View
style={{
flexDirection: "row",
width: "100%",
margin: 10,
}}
>
<Text>{item.name}</Text>
<TouchableOpacity
style={{ width: 100, height: 50, backgroundColor: color }}
onPress={() => onPressHandler(item.id)}
/>
</View>
);
}, (prevProps, nextProps) => {
if (prevProps.item.isFav === nextProps.item.isFav) return true;
return false;
});
const PlanerScreen = () => {
const [listData, setListData] = useState([
{ id: "1", name: "Banana", isFav: true },
{ id: "2", name: "Apple", isFav: false },
]);
const favHandler = useCallback((id) => {
setListData(prevState => {
return prevState.map((item) =>
item.id === id ? { ...item, isFav: !item.isFav } : item
)
}
);
}, []);
console.log("### FlatList rendered #####");
return (
<View style={styles.container}>
<FlatList
data={listData}
renderItem={({ item }) => <Item item={item} onPressHandler={favHandler} />}
keyExtractor={keyExtractor}
/>
</View>
);
};
export default PlanerScreen;