如何解决使用无限滚动加载数据引起的死循环问题

时间:2019-06-09 11:48:19

标签: javascript reactjs react-redux

大家好,我正在通过youtube v3 api创建辅助项目

基于实践,由于某种原因,我必须使用旧版本的react + redux来完成此附带项目

反应:v16.4.2 Redux:v5.0.7

UI库 蚂蚁:v3.10.9 样式组件:v3.4.6

在搜索页面中,我想对“无限滚动”使用延迟加载。

所以我“ react-infinite-scroller”这个工具包,当滚动到底部时,重新调用api并执行setState以达到重新渲染的效果。

但是我发现当前执行重新渲染的方法是通过生命周期,getDerivedStateFromProps和componentDidUpdate 导致无限循环问题

因为加载新项目时,它将触发滚动条调用api的条件,以便屏幕进入setState的无限循环问题。希望您能提供帮助。

查看组件

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import InfiniteScroll from 'react-infinite-scroller';
import styled from 'styled-components';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {PortalRedux, SearchRedux} from '../../Redux/Modules';
import {Header} from '../../Components/Layout';
import {VideoListPlayItem, ListDropdown} from '../../Components/Modules';
import {formatData} from '../../Common/BasicService';
import {googleApiKey} from '../../ApiCenter/Api/Api';
import * as ComponentConfig from '../../Common/ComponentConfig';
import * as Style from '../../Common/Style';

const SearchView = styled.div`
    width: 100%;
    height: 90vh;
`;

const SearchContent = styled.div`
    width: 100%;
    height: 100%;
    padding: 2% 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
`;

const AdvancedSearch = styled.div`
    height: 4vh;
    minHeight: 60px;
`;

const infiniteScrollDomStyle = {
    width: '100%',
    height: '90vh',
    padding: '0 8%',
    overflow: 'auto'
};

const btnConfig = {
    color: `${Style.FontStressColor}`,
    border: 0,
    marginLeft: 8
};

const VideoListPlayItemConfig = {
    width: '100%',
    marginBottom: '2rem',
    displayWidth: 320,
    playerConfig: {
        width: '320px',
        height: '180px',
        defaultControls: false,
        showControl: false,
        defaultPlay: true,
        mute: true
    },
    playerInlineConfig: {
        minWidth: '600px',
        minHeight: '18px'
    }
};

class Search extends Component {

    constructor(props) {
        super(props);
        this.state = {
            searchStatus: false,
            searchKey: '',
            nextPageToken: '',
            searchResult: [],
        };
    }

    static getDerivedStateFromProps(nextProps) {
        switch (nextProps.action.type) {
            case SearchRedux.SearchActions.getSearchSuccess:
                return {
                    searchStatus: true,
                    searchKey: action.payload.config.params.q,
                    nextPageToken: nextProps.action.payload.nextPageToken,
                    searchResult: nextProps.action.payload.items
                };
            default:
                break;
        }
        return null;
    }

    componentDidUpdate(nextProps) {
 // If you use this.setState to refresh data, this will result in an infinite loop.
        if (this.state.searchStatus) {
            this.setState({
                searchStatus: false,
                searchKey: action.payload.config.params.q,
                nextPageToken: nextProps.action.payload.nextPageToken,
                searchResult: nextProps.action.payload.items
            });
        }
    }


    getNextLoadSearchData = () => {
        const request = {
            part: 'snippet',
            maxResults: 10,
            q: this.state.searchKey,
            type: 'video',
            pageToken: this.state.nextPageToken,
            key: googleApiKey
        };
        this.props.SearchActionsCreator.getSearchResultData(request);
    };

    render() {
        return (
            <div>
                <Header/>
                <SearchView>
                    <AdvancedSearch>
                        <ListDropdown
                            configData={ComponentConfig.DateSearchDropdown}
                            btnConfig={btnConfig}
                            itemClickAction={this.props.PortalActionsCreator.changeToPage}
                        />
                        <ListDropdown
                            configData={ComponentConfig.TypeSearchDropdown}
                            btnConfig={btnConfig}
                            itemClickAction={this.props.PortalActionsCreator.changeToPage}
                        />
                    </AdvancedSearch>
                    <div style={infiniteScrollDomStyle} ref={(ref) => this.scrollParentRef = ref}>
                        <InfiniteScroll
                            threshold={250}
                            hasMore={true}
                            initialLoad={false}
                            isReverse={false}
                            useWindow={true}
                            loadMore={this.getNextLoadSearchData}
                            getScrollParent={() => this.scrollParentRef}
                        >
                            <SearchContent>
                                {
                                    this.state.searchResult.length !== 0
                                        ? formatData.videoListPlayItemRespond(this.state.searchResult).map((item) => {
                                            return (
                                                <VideoListPlayItem
                                                    key={item.id}
                                                    VideoListPlayItemConfig={VideoListPlayItemConfig}
                                                    VideoListPlayItemData={
                                                        {
                                                            title: item.title,
                                                            description: item.description,
                                                            playData: item.playData,
                                                            thumbnailURL: item.imgURL
                                                        }
                                                    }
                                                />
                                            );
                                        })
                                        : <div>No-Data</div>
                                }
                            </SearchContent>
                        </InfiniteScroll>
                    </div>
                </SearchView>
            </div>
        );
    }
}

Search.propTypes = {
    PortalActionsCreator: PropTypes.object.isRequired,
    SearchActionsCreator: PropTypes.object.isRequired,
};

export default connect(
    (state) => {
        return {action: state.SearchReducer.action};
    },
    (dispatch) => {
        return {
            PortalActionsCreator: bindActionCreators(PortalRedux.PortalActionsCreator, dispatch),
            SearchActionsCreator: bindActionCreators(SearchRedux.SearchActionsCreator, dispatch),
        };
    }
)(Search);

Redux

import {createAction} from 'redux-actions';
import {callApi} from '../../../ApiCenter/Api/CallApi';
import * as apiData from '../../../ApiCenter/Api/Api';

export const SearchActions = {
    getSearchStart: 'GET_SEARCH_START',
    getSearchSuccess: 'GET_SEARCH_SUCCESS',
    getSearchFailed: 'GET_SEARCH_FAILED',
};

const getSearchResultData = (request) => {
    return (dispatch) => {
        dispatch(createAction(SearchActions.getSearchStart)());
        callApi.get(apiData.searchURL, request)
            .then((respond) => {
                dispatch(createAction(SearchActions.getSearchSuccess(request))(respond));
            })
            .catch((error) => {
                dispatch(createAction(SearchActions.getSearchFailed)(error));
            });
    };
};

export const SearchActionsCreator = {
    getSearchResultData,
};

export default function SearchReducer(state = {action: ''}, action) {
    switch (action.type) {
        case SearchActions.getSearchSuccess:
        case SearchActions.getSearchFailed:
            return {action: action};

        default:
            return state;
    }
}


现在,进入搜索页面后,react将继续进入setState并呈现为错误。我不知道如何控制“ componentDidUpdate”周的“ this.state.searchStatus”。这个问题。

请帮助我,我很感激!

0 个答案:

没有答案