繁体   English   中英

在 React 上使用 Algolia 的无限滚动

[英]Infinite Scroll using Algolia on React

我正在尝试在我的反应应用程序上实现无限滚动,以获取来自 Algolia 的搜索命中。

我在他们的文档中遇到了一个 class 组件。 我使用 React Hooks 所以试图让它在 React Hooks 上工作。 我得到的只是这么多的渲染,当这个组件安装时我的应用程序被挂断了。

这是我的代码:

import React, { useEffect, useRef } from 'react';
import Card from '@material-ui/core/Card';
import CardActionArea from '@material-ui/core/CardActionArea';
import CardActions from '@material-ui/core/CardActions';
import CardContent from '@material-ui/core/CardContent';
import CardMedia from '@material-ui/core/CardMedia';
import Button from '@material-ui/core/Button';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import Container from '@material-ui/core/Container';
import Grid from '@material-ui/core/Grid';
import { connectHits, connectInfiniteHits } from 'react-instantsearch-dom';
import noItemImage from './../../assets/img/noItemImage.png'
import { Link } from 'react-router-dom'
import ShareIcon from '@material-ui/icons/Share';
import PropTypes from 'prop-types';

function AlgoliaHits(props) {
    const { hits } = props
    console.log(hits)
    var sentinel = useRef(null)
    
    useEffect(() => {
        function onSentinelIntersection (entries){
            const { hasMore, refine } = props

            entries.forEach(entry => {
                if (entry.isIntersecting && hasMore) {
                    refine()
                }
            })
        }

        var observer = new IntersectionObserver(onSentinelIntersection, {})

        observer.observe(sentinel.current)
        return () => {
            observer.disconnect()
        }
    }, [props])

    return (
        <Container maxWidth="md" style={{ marginBottom: 100 }}>
            <Grid container spacing={2}>
                {
                    hits.map(hit => (
                        <Grid item xs={12} sm={6} md={4} lg={4} xl={3}>
                            <Link to={`/item/${hit.item_id}`} style={{ textDecoration: 'none' }}>
                                <Card maxWidth={210} key={hit.item_id} elevation={0}>
                                    <CardActionArea>
                                        <CardMedia
                                            component="img"
                                            alt="Contemplative Reptile"
                                            height="140"
                                            image={
                                                hit.item_images_url ? 
                                                    hit.item_images_url.length === 0 ?
                                                    noItemImage
                                                    :
                                                    hit.item_images_url[0]
                                                : 
                                                noItemImage
                                            }
                                            title={hit.item_name}
                                        />
                                        <CardContent>
                                            <Typography gutterBottom variant="h5" component="h2"
                                                style={{ whiteSpace: 'nowrap', width: 250, overflow: 'hidden', textOverflow: 'ellipsis' }}>
                                                {hit.item_name}
                                            </Typography>
                                            <Typography variant="body2" color="textSecondary" component="p" 
                                                style={{ whiteSpace: 'nowrap', width: 200, overflow: 'hidden', textOverflow: 'ellipsis'  }}>
                                                {hit.item_description}
                                    </Typography>
                                        </CardContent>
                                    </CardActionArea>
                                    <CardActions>
                                        <Button size="small" color="primary" component={Link} to={`/item/${hit.item_id}`}>
                                            View
                                        </Button>
                                        <IconButton size="small" color="secondary">
                                            <ShareIcon style={{ padding: 4 }}/>
                                        </IconButton>
                                    </CardActions>
                                </Card>
                            </Link>
                        </Grid>                        
                    ))
                }
            </Grid>
            <div id="sentinel" ref={sentinel} />
        </Container>
    );
}

AlgoliaHits.propTypes = {
    hits: PropTypes.arrayOf(PropTypes.object).isRequired,
    hasMore: PropTypes.bool.isRequired,
    refine: PropTypes.func.isRequired,
}

const AlgoliaInfiniteScroll = connectHits(AlgoliaHits)

const ItemCard = connectInfiniteHits(AlgoliaInfiniteScroll)

export default ItemCard

这里是我使用参考的地方。 我在做什么错? 以及如何解决?

TIA

我的第一个想法是问题可能出在useEffect依赖数组中。

只要其中一个依赖项发生更改, useEffect挂钩就会触发。 在您的情况下,您已将依赖项数组指定为[props] ,这意味着每次道具更改时,它都会再次触发。 由于props可能经常变化,对于props.hits等对象,我敢打赌这是将您的代码投入您提到的无限循环中。

我相信在原始示例中, onSentinelIntersection功能仅在组件安装时发生一次。

我将从一个空的依赖数组开始: []在你的 useEffect 的末尾。 这是替换componentDidMount并且仅在组件第一次渲染时运行一次(尽管有点 hacky)的方法。

如果这有帮助,那么您可能已经成功了。 但是,我还建议将onSentinelIntersection function 从useEffect中移出(如果可能的话,甚至完全从组件中移出。)-因为最好将尽可能多的代码保留在 useEffect 之外(因为它将是每次执行时评估)。

所以像:

function AlgoliaHits(props) {
    const { hits } = props
    console.log(hits)
    var sentinel = useRef(null)
    
    function onSentinelIntersection (entries){
        const { hasMore, refine } = props

        entries.forEach(entry => {
            if (entry.isIntersecting && hasMore) {
                refine()
            }
        })
    }

    useEffect(() => {
        var observer = new IntersectionObserver(onSentinelIntersection, {})
        observer.observe(sentinel.current)

        return () => observer.disconnect()
    }, [])

    ....

可能是一个好的开始。 您也可以安全地将[IntersectionObserver, onSentinelIntersection]添加到useEffect依赖项中,因为它们在技术上是 useEffect 到 function 所必需的,并且在这种情况下不应导致任何进一步的useEffect触发器。

React useEffect 文档Dependencies & Performance部分在这里很有帮助——以及整个页面本身。

对于额外的资源,我真的从 Dan Abramov 的The Complete Guide To useEffect中获得了很多收获——读了很久,但我认为值得(当你有时间的时候,就是这样!)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM