Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 如何使用带有平面列表和React钩子的无限滚动?_Reactjs_React Native_React Native Flatlist - Fatal编程技术网

Reactjs 如何使用带有平面列表和React钩子的无限滚动?

Reactjs 如何使用带有平面列表和React钩子的无限滚动?,reactjs,react-native,react-native-flatlist,Reactjs,React Native,React Native Flatlist,我正在重构React钩子,但我无法在FlatList工作的情况下获得无限滚动 const [page, setPage] = useState(1); 这是我的useEffect挂钩: useEffect(() => { const loadProducts = async () => { setIsLoading(true); let response = await fetch(`${api}&page=${page}&perPage=5`)

我正在重构React钩子,但我无法在FlatList工作的情况下获得无限滚动

const [page, setPage] = useState(1);
这是我的useEffect挂钩:

useEffect(() => {
  const loadProducts = async () => {
    setIsLoading(true);
    let response = await fetch(`${api}&page=${page}&perPage=5`);
    let results = await response.json();
    setProducts([...products, ...results.data]);
    setIsLoading(false);
  };
  loadProducts();
}, [page]);
偏移量为
${page}
,限制为
&每页=5
(硬编码为
5

平面列表:

<FlatList
  data={products}
  keyExtractor={(item) => item.id}
  renderItem={renderGridItem}
  onEndReached={loadMore}
  onEndThreshold={0.3}
/>;
const loadMore = () => {
  setPage(page + 1);
};

理论上,这应该是可行的,不是吗?

在这种情况下,尝试使用
useCallback
而不是
useffect
。此外,我还向您展示了如何防止将空结果传播到
setState

const loadProducts=async()=>{
设置加载(真);
let response=wait-fetch(`${api}&page=${page}&perPage=5`);
让results=wait response.json();
if(结果数据){
setProducts([…产品,…结果.数据]);
}
设置加载(假);
};
useffect(()=>{
loadProducts();
}, [])
const onLoadMore=useCallback(()=>{
loadProducts();
}
有关
useCallback
的更多信息,请阅读此说明。

说明

我自己也在努力解决这个问题。下面是一个使用分区列表的示例(基本上与平面列表相同)

标题编号表示发送到API的请求编号。您可以通过单击“检查编号”按钮来检查请求的顺序是否正确,并且没有重复项

在本例中,我们使用模拟获取某些数据

该示例还实现了拉入刷新。同样,您可以通过单击“检查长度”按钮来检查拉入刷新后数组的长度是否符合预期

世博小吃

确保在零食中将平台更改为iOS或Android(网络将不起作用)

代码

import*as React from'React';
从“react native”导入{ActivityIndicator}
var=需要('lodash'))
进口{
样式表,
文本,
看法
安全区域视图,
章节列表,
按钮
刷新控制
}从“反应本机”;
功能项(项){
返回(
{item.title.first_name}
);
}
导出默认函数testSectionList({navigation}){
const[data,setData]=React.useState()
常量[loading,setLoading]=React.useState(true)
const[refreshing,setRefreshing]=React.useState(false);
常量[showRefreshingIndicator,setShowRefreshingIndicator]=React.useState(false);
const dataIndex=React.useRef(0);
const totalHits=React.useRef(42);//在实际示例中:使用api的第一个结果更新此
常量fetchData=async(重置:布尔)=>{
如果(重置===true)dataIndex.current=0;
//如果API中没有更多数据,请确保返回
if(dataIndex.current!==0&&dataIndex.current>=totalHits.current)返回[]
//例如,选择一个随机页面
const fakepage=Math.round(Math.random())*2
const resultObject=等待获取(`https://reqres.in/api/users?page=${fakepage}`);
const result=await resultObject.json()
dataIndex.current++;
返回{
标题:`${dataIndex.current-1}`,
数据:等待结果。数据
}
}
常数计数=()=>{
警报(数据长度)
}
常量checkPageNumber=()=>{
const number=data.map(item=>parseInt(item.title))
常量增量=[…数组(data.length).keys()]
警报(u.isEqual(数字,增量))
}
const getInitialData=async()=>{
const list=等待获取数据(false)
如果(!list)返回
setData([列表])
设置加载(错误)
}
React.useffect(()=>{
getInitialData()
}, [])
const onEndReached=async()=>{
const newItems=等待获取数据(false)
如果(!newItems.data.length)返回
setData([…数据,newItems])
}
const onRefresh=React.useCallback(异步()=>{
设置ShowRefreshingIndicator(真);
const newItems=等待获取数据(true)
setData([newItems])
设置ShowRefreshingIndicator(假)
},[刷新];
如果(加载)返回加载。。。
返回(
CheckPageNumber()}/>
count()}/>
{
如果(刷新)返回;
设置刷新(真)
onEndReached()。然后(()=>{
设置刷新(错误)
})
}}
onEndReachedThreshold={1}
keyExtractor={(项,索引)=>item+index}
renderItem={({item})=>}
renderSectionHeader={({section:{title}}})=>(
{title}
)}
ListFooterComponent={}
stickySectionHeadersEnabled={false}
/>
);
}
const styles=StyleSheet.create({
容器:{
弹性:1,
玛金托普:40,
marginHorizontal:16,
},
项目:{
背景颜色:“#f9c2ff”,
填充:2,
第二,,
},
标题:{
尺寸:16,
},
标题:{
尺寸:12,
},
});

您能详细解释一下它是如何不起作用的吗?是否有任何错误?或者只是ONEDREACHED没有被调用?它以某种方式起作用,但并不像预期的那样。首先,它似乎实际加载了更多页面,但在获取新数据时它总是跳到列表的顶部。如果我的项目结束,我会得到错误:[未处理的承诺拒绝:TypeError:传播不可编辑实例的尝试无效]对于跳转到最上面的问题,我想这是因为您更改了组件的状态。对于TypeError,当您滚动到末尾并且没有任何东西可以加载时,
结果。数据
将是
null
。因此您不能将null对象扩展到setState。但是,如果您通过codesandbox共享代码以使其他人看看你的应用程序。谢谢。你知道如何防止它跳到顶端吗?我想useEffect会把[page]作为一个例子
import * as React from 'react';
import { ActivityIndicator } from 'react-native'
var _ = require('lodash')

import {
    StyleSheet,
    Text,
    View,
    SafeAreaView,
    SectionList,
    Button,
    RefreshControl
} from 'react-native';

function Item(item) {
    return (
        <View style={styles.item}>
            <Text style={styles.title}>{item.title.first_name}</Text>
        </View>
    );
}

export default function testSectionList({ navigation }) {

    const [data, setData] = React.useState()
    const [loading, setLoading] = React.useState(true)
    const [refreshing, setRefreshing] = React.useState(false);
    const [showRefreshingIndicator, setShowRefreshingIndicator] = React.useState(false);

    const dataIndex = React.useRef(0);
    const totalHits = React.useRef(42); // In real example: Update this with first result from api

    const fetchData = async (reset: boolean) => {

        if (reset === true) dataIndex.current = 0;

        // Make sure to return if no more data from API
        if (dataIndex.current !== 0 && dataIndex.current >= totalHits.current) return []

        // For example usage, select a random page
        const fakepage = Math.round(Math.random()) * 2
        const resultObject = await fetch(`https://reqres.in/api/users?page=${fakepage}`);
        const result = await resultObject.json()

        dataIndex.current++;

        return {
            title: `${dataIndex.current-1}`,
            data: await result.data
        }
    }

    const count = () => {
        alert(data.length)
    }

    const checkPageNumbers = () => {
        const numbers = data.map(item => parseInt(item.title))
        const incremental = [...Array(data.length).keys()]

        alert(_.isEqual(numbers, incremental))
    }

    const getInitialData = async () => {

        const list = await fetchData(false)
        if(!list) return

        setData([list])

        setLoading(false)
    }

    React.useEffect(() => {
        getInitialData()
    }, [])

    const onEndReached = async () => {
        const newItems = await fetchData(false)
        if(!newItems.data.length) return
        setData([...data, newItems])
    }

    const onRefresh = React.useCallback(async () => {
        setShowRefreshingIndicator(true);

        const newItems = await fetchData(true)
        setData([newItems])

        setShowRefreshingIndicator(false)

    }, [refreshing]);

    if (loading) return <Text>Loading...</Text>

    return (
        <SafeAreaView style={styles.container}>
            <Button title={"Check numbers"} onPress={() => checkPageNumbers()} />
            <Button title={"Check length"} onPress={() => count()} />
            <SectionList
                sections={data}
                refreshing={refreshing}
                refreshControl={
                    <RefreshControl refreshing={showRefreshingIndicator} onRefresh={onRefresh} />
                }
                onEndReached={() => {
                    if(refreshing) return;
                    setRefreshing(true)
                    onEndReached().then(() => {
                        setRefreshing(false)
                    })
                }}
                onEndReachedThreshold={1}
                keyExtractor={(item, index) => item + index}
                renderItem={({ item }) => <Item title={item} />}
                renderSectionHeader={({ section: { title } }) => (
                    <Text style={styles.header}>{title}</Text>
                )}
                ListFooterComponent={<ActivityIndicator size={"large"} />}
                stickySectionHeadersEnabled={false}
            />
        </SafeAreaView>
    );

}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        marginTop: 40,
        marginHorizontal: 16,
    },
    item: {
        backgroundColor: '#f9c2ff',
        padding: 2,
        marginVertical: 2,
    },
    header: {
        fontSize: 16,
    },
    title: {
        fontSize: 12,
    },
});