Как создать бесконечную прокрутку в React и Redux?

#reactjs #redux #axios

#reactjs #redux #axios

Вопрос:

 import React, {useState, useEffect} from 'react';
import {connect} from 'react-redux';

import {
    fetchRecipes
} from '../../store/actions';
import './BeerRecipes.css';

const BeerRecipes = ({recipesData, fetchRecipes}) => {

    const [page, setPage] = useState(1);
    const [recipes, setRecipes] = useState([]);
    const [loading, setLoading] = useState(true);


    useEffect(() => {
        fetchRecipes();
    }, [])

    return (

                <div className='beer_recipes_block'>
                    <div className='title_wrapper'>
                        <h2 className='title'>Beer recipes</h2>
                    </div>
                    <div className='beer_recipes'>
                        <ul className='beer_recipes_items'>
                            {
                                recipesData amp;amp; recipesData.recipes amp;amp; recipesData.recipes.map(recipe =>
                                    <li className='beer_recipes_item' id={recipe.id}>{recipe.name}</li>
                                )
                            }
                        </ul>
                    </div>
                </div>

    );
};

const mapStateToProps = state => {
    return {
        recipesData: state.recipes
    }
}

const mapDispatchToProps = dispatch => {
    return {
        fetchRecipes: () => dispatch(fetchRecipes())
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(BeerRecipes);
 

это мой компонент, в котором я хотел бы создать бесконечную прокрутку, а ниже — мое redux-действие с axios:

 import axios from "axios";
import * as actionTypes from "./actionTypes";

export const fetchRecipesRequest = () => {
    return {
        type: actionTypes.FETCH_RECIPES_REQUEST
    }
}

export const fetchRecipesSuccess = recipes => {
    return {
        type: actionTypes.FETCH_RECIPES_SUCCESS,
        payload: recipes
    }
}

export const fetchRecipesFailure = error => {
    return {
        type: actionTypes.FETCH_RECIPES_FAILURE,
        payload: error
    }
}

export const fetchRecipes = (page) => {
   return (dispatch) => {
       dispatch(fetchRecipesRequest)
        axios
            .get('https://api.punkapi.com/v2/beers?page=1')
            .then(response => {
                const recipes = response.data;
                dispatch(fetchRecipesSuccess(recipes));
            })
            .catch(error => {
                const errorMsg = error.message;
                dispatch(fetchRecipesFailure(errorMsg));
            })
   }
}
 

Я хочу создать прокрутку. Мне нужно, во-первых, отобразить первые 10 элементов, а затем добавить 5 элементов при каждой загрузке. Всего у меня 25 элементов, и когда список будет готов, он должен снова начинаться с первых пяти.

Ответ №1:

Предполагая, что у вас уже все готово для загрузки следующей страницы. Вероятно, вы можете упростить весь процесс, используя пакет, подобный react-in-viewport, чтобы вам не приходилось иметь дело со всеми прослушивателями прокрутки.

затем вы используете его следующим образом.

 import handleViewport from 'react-in-viewport';
 
const Block = (props: { inViewport: boolean }) => {
  const { inViewport, forwardedRef } = props;
  const color = inViewport ? '#217ac0' : '#ff9800';
  const text = inViewport ? 'In viewport' : 'Not in viewport';
  return (
    <div className="viewport-block" ref={forwardedRef}>
      <h3>{ text }</h3>
      <div style={{ width: '400px', height: '300px', background: color }} />
    </div>
  );
};
 
const ViewportBlock = handleViewport(Block, /** options: {}, config: {} **/);
 
const Component = (props) => (
  <div>
    <div style={{ height: '100vh' }}>
      <h2>Scroll down to make component in viewport</h2>
    </div>
    <ViewportBlock 
         onEnterViewport={() => console.log('This is the bottom of the content, lets dispatch to load more post ')} 
         onLeaveViewport={() => console.log('We can choose not to use this.')} />
  </div>
))
 

Что здесь происходит, так это то, что он создает «div», который находится за пределами области просмотра, как только он попадает в порт просмотра (это означает, что пользователь уже прокрутил страницу вниз), вы можете вызвать функцию для загрузки дополнительной записи.

На заметку: не забудьте добавить какой-нибудь дроссель в вашу функцию выборки.