我正在使用Hooks和ES6构建一个React Native App。
主屏幕从API中获取一些数据,并以图片库的形式显示出来.主屏幕是父组件,它包括一个幻灯片库和一个Flatlist作为子组件。
1) Slideshow - 图片库自动播放,在每次图片迭代(每3秒)时运行一些操作(在用户点击它们的情况下获取URL) - 这将导致整个父组件及其子组件的重新渲染,但它每3秒渲染一次。
2)Flatlist - 只是一个简单的Flatlist,需要一个图像数组 - 这个 只应渲染一次 当父组件被首先加载时
问题
每隔3秒就会在幻灯片中显示一张新的图片,运行一个函数为显示的图片获取一些道具,父组件被重新渲染,但不需要在第二个图库中的Flatlist再次运行,因为图片数组和最初加载的一样(没有改变)。
这是我的母体代码
const getTopTenMovies = (state) => state.moviescreen.popularmovies //fetching data from Redux
const upcomingMovies = (state) => state.moviescreen.upcomingmovies
const MoviesScreen = (props) => {
const topTenMovies = useSelector(getTopTenMovies);
const [imageIndex, setImageIndex] = useState("");
/* useEffect below runs every time imageIndex changes (a new image is displayed every 3 secs) */
useEffect(() => {
setCarouselMovieId(selectedImageItem.id);
setCarouselMovieTitle(selectedImageItem.title);
}, [imageIndex]);
/* user clicks on an image and is taken to another screen
const fetchMovieHandler = async (movieId, movieTitle) => {
props.navigation.navigate({
routeName: "MovieDetail",
params: {
assetId: movieId,
assetName: movieTitle,
},
});
};
return (
<ImageGallery
data={topTenMovies}
currentImage=setImageIndex(index)
...
/>
<View style={styles.containerRow}>
<FlatList
horizontal={true}
data={upcomingMovies}
initialNumToRender={5}
windowSize={10}
removeClippedSubviews={true}
keyExtractor={(item) => item.id.toString()}
renderItem={(itemData) => (
<HomeItem
id={itemData.item.id}
poster={itemData.item.poster_path}
onAssetSelection={fetchMovieHandler}
/>
)}
/>
</View>
</View>
)
}
该组件渲染Flatlist中的各个图片,并将参数(movieId,movieTitle)传递给fetchMovieHandler函数。
下面是HomeItem的代码...
class HomeItem extends React.PureComponent {
render() {
const assetHandler = async () => {
this.props.onAssetSelection(this.props.id, this.props.title);
};
console.log("HomeItem is called");
return (
<TouchableOpacity onPress={assetHandler}>
<View>
<Image
key={this.props.id}
source={{
uri: `https://*******${this.props.poster}`,
}}
/>
</View>
</TouchableOpacity>
);
}
}
export default React.memo(HomeItem);
每隔3秒,HomeItem被调用,我看到10个日志条目(每个图像和渲染一个 - upcomingMovies有10个图像)。从用户界面上看,一切都很好,因为图像似乎没有改变,可能是因为我已经将HomeItem定义为PureComponent,并使用React.memo(HomeItem),但这造成了性能问题,因为我得到以下错误。
VirtualizedList: 你的列表很大,更新速度很慢--确保你的renderItem函数渲染的组件遵循React性能最佳实践,如PureComponent、shouldComponentUpdate等。
我试图在HomeItem组件中包含Flatlist,但问题依然存在。
如果我是你,我会修改以下内容。
Component
延期而不是 PureComponent
并将您的道具与`shouldComponentUpdate.ComponentUpdate进行比较。我认为传递的函数onAssetSelection会导致重新渲染。检查一下)。) React.memo
因为它是针对功能组件的。经过进一步的研究,并感谢@landorid的建议,我发现我需要通过在一个单独的函数中声明FlatList的renderItem,并使用回调钩和依赖我的数据源来控制它。
我试着将Flatlist包含在一个单独的PureComponent中,但重新渲染的情况一直在发生。
理想的解决方案是修改这段代码
renderItem={(itemData) => (
<HomeItem
id={itemData.item.id}
poster={itemData.item.poster_path}
onAssetSelection={fetchMovieHandler}
/>
)}
变成这样
.....
const renderRow = ({ itemData }) => {
return (
<HomeItem
id={itemData.item.id}
poster={itemData.item.poster_path}
title={itemData.item.title}
onAssetSelection={fetchMovieHandler}
/>
);
};
keyExtractor = (item) => item.id.toString();
return (
<FlatList
horizontal={true}
data={upcomingMovies}
initialNumToRender={5}
windowSize={10}
removeClippedSubviews={true}
keyExtractor={keyExtractor}
renderItem={renderRow}
/>
然后将renderRow()函数封装在一个useCallback钩子中。
问题是我的数据源data={upcomingMovies}是一个2层的对象数组,我需要使用itemData.item.title来检索标题值。
虽然它在我当前的renderItem设置中可以工作,但当我在外部函数中使用它时却无法工作,例如
const renderRow = ({ itemData }) => {
return (
<HomeItem
id={itemData.item.id}
poster={itemData.item.poster_path}
title={itemData.item.title}
onAssetSelection={fetchMovieHandler}
/>
);
};
我只是得到,"项目 "变量不可用。
有什么建议,如何修改这个功能?