选项卡导航器内的 Flatlist 在 React Native 状态变化时滚动到顶部
Flatlist inside tab navigator is scrolling to top on state change in react native
Here you can see the gif
这是我的整个 Navigator 功能组件。我正在尝试使用 Tab Navigator 实现两个选项卡。一个显示加密货币,另一个显示外汇数据。
问题是,当我尝试在到达平面列表的末尾时加载更多数据时,平面列表滚动到顶部,因为我正在进行状态更改 [page+1]。
const Navigator = () => {
const Tab = createMaterialTopTabNavigator();
const renderItems = ({ item }) => (
<Text>{item.name}<Text>
);
const fetchMarketData = async () => {
console.log("Fetching");
const marketData = await getCryptoMarketData({ page });
if (marketData != "Network Error") {
const ids = data.map((item) => item.id);
let newData = marketData.filter((item) => !ids.includes(item.id));
setData([...data, ...newData]);
setFetching(false);
} else {
setFetching(false);
Alert.alert(marketData, "Sorry for the inconvenience");
}
};
useEffect(() => {
setFetching(true);
const data = async () => {
await fetchMarketData();
};
}, [page]);
const handleLoadMore = async () => {
setFetching(true);
setPage((page) => page + 1);
};
const ScreenA = () => (
<FlatList
data={data}
style={{ backgroundColor: "white" }}
keyExtractor={(item) => item.id}
renderItem={renderItems}
scrollEventThrottle={16}
onEndReached={handleLoadMore}
onEndReachedThreshold={0}
/>
);
return (
<Tab.Navigator
screenOptions={({ route }) => screenOptions(route)}
keyboardDismissMode="auto"
>
<Tab.Screen name="Crypto" component={ScreenA} />
<Tab.Screen name="Forex" component={ScreenC} />
</Tab.Navigator>
);
};
export default Navigator;
OnEndReached 正在触发 handleLoadMore 函数,在数据状态更改后,Flatlist 滚动到顶部。
第一个原因
- 你在“fetchMarketData”中有错字,你究竟是如何得到“newData”的,因为我在任何地方都看不到它,也许它应该是“marketData”,如果不是那么你添加相同的旧数据加上未定义的
[...data, ...undefined]
第二个原因
你调用 setPage(page + 1)
然后调用“fetchMarketData”的原因,这很糟糕,为什么?因为 setState 是异步的,它可以立即或在 5 秒后改变,所以你不知道它什么时候改变的,这就是我们有钩子的原因,你可以使用“useEffect”来处理这个
像这样更改您的“handleLoadMore”
const handleLoadMore = () => {
setPage(page + 1);
};
添加在“页面”状态更改时运行的 useEffect 挂钩
React.useEffect(() => {
(async() => {
setFetching(true)
const marketData = await getCryptoMarketData({ page });
if (marketData != "Network Error") {
setData([...data, ...marketData]);
} else {
Alert.alert(marketData, "Sorry for the inconvenience");
}
setFetching(false)
})()
}, [page])
Here you can see the gif
这是我的整个 Navigator 功能组件。我正在尝试使用 Tab Navigator 实现两个选项卡。一个显示加密货币,另一个显示外汇数据。
问题是,当我尝试在到达平面列表的末尾时加载更多数据时,平面列表滚动到顶部,因为我正在进行状态更改 [page+1]。
const Navigator = () => {
const Tab = createMaterialTopTabNavigator();
const renderItems = ({ item }) => (
<Text>{item.name}<Text>
);
const fetchMarketData = async () => {
console.log("Fetching");
const marketData = await getCryptoMarketData({ page });
if (marketData != "Network Error") {
const ids = data.map((item) => item.id);
let newData = marketData.filter((item) => !ids.includes(item.id));
setData([...data, ...newData]);
setFetching(false);
} else {
setFetching(false);
Alert.alert(marketData, "Sorry for the inconvenience");
}
};
useEffect(() => {
setFetching(true);
const data = async () => {
await fetchMarketData();
};
}, [page]);
const handleLoadMore = async () => {
setFetching(true);
setPage((page) => page + 1);
};
const ScreenA = () => (
<FlatList
data={data}
style={{ backgroundColor: "white" }}
keyExtractor={(item) => item.id}
renderItem={renderItems}
scrollEventThrottle={16}
onEndReached={handleLoadMore}
onEndReachedThreshold={0}
/>
);
return (
<Tab.Navigator
screenOptions={({ route }) => screenOptions(route)}
keyboardDismissMode="auto"
>
<Tab.Screen name="Crypto" component={ScreenA} />
<Tab.Screen name="Forex" component={ScreenC} />
</Tab.Navigator>
);
};
export default Navigator;
OnEndReached 正在触发 handleLoadMore 函数,在数据状态更改后,Flatlist 滚动到顶部。
第一个原因
- 你在“fetchMarketData”中有错字,你究竟是如何得到“newData”的,因为我在任何地方都看不到它,也许它应该是“marketData”,如果不是那么你添加相同的旧数据加上未定义的
[...data, ...undefined]
第二个原因
你调用 setPage(page + 1)
然后调用“fetchMarketData”的原因,这很糟糕,为什么?因为 setState 是异步的,它可以立即或在 5 秒后改变,所以你不知道它什么时候改变的,这就是我们有钩子的原因,你可以使用“useEffect”来处理这个
像这样更改您的“handleLoadMore”
const handleLoadMore = () => {
setPage(page + 1);
};
添加在“页面”状态更改时运行的 useEffect 挂钩
React.useEffect(() => {
(async() => {
setFetching(true)
const marketData = await getCryptoMarketData({ page });
if (marketData != "Network Error") {
setData([...data, ...marketData]);
} else {
Alert.alert(marketData, "Sorry for the inconvenience");
}
setFetching(false)
})()
}, [page])