React Native FlatList gets infinity loop onRefresh

丶灬走出姿态 提交于 2019-12-25 00:11:17

问题


Im trying to fetch data from redux to a FlatList and onRefresh={} gives me an infinity loop. When i dont use redux it works but when i moved my fetching into a redux action im getting confused.

Can someone describe to me what I am doing wrong?

Thanks in advance.

use my snack: https://snack.expo.io/@thesvarta/redux-with-flatlist

Heres my component

    import React, { Component } from 'react';
    import { connect } from 'react-redux';
    import {
      View,
      Text,
      FlatList,
      StatusBar,
      StyleSheet,
      ActivityIndicator,
      TouchableOpacity,
      TouchableHighlight,
      Image,
      Button,
      SearchBar,
      TextInput,
    } from 'react-native';
    import TextDetails from '../TextDetails/TextDetails';
    import {
      fetchDataOptions,
      resetDataOptions,
      selectOptions,
    } from '../store/actions/index';
    class Search extends Component {
      constructor(props) {
        super(props);
        this.state = {
          page: 1,
          loading: false,
          refreshing: false,
        };
      }
      componentDidMount() {
        this.props.onResetDataOptions();
        this.props.onFetchDataOptions(this.state.page, this.props.GroupBy);
        console.log('component_data', this.props.fetch_data_options);
      }
      handleRefresh = () => {
        this.props.onResetDataOptions(); // Resets fetch_data_options
        this.setState(
          {
            page: 1,
            refreshing: true,
          },
          () => {
            this.props.onFetchDataOptions(this.state.page, this.props.GroupBy);
          }
        );
      };

      handleLoadMore = () => {
        if (!this.props.fetch_data_error) {
          this.setState(
            {
              page: this.state.page + 1,
            },
            () => {
              this.props.onFetchDataOptions(this.state.page, this.props.GroupBy);
              console.log('load_more', this.state.page);
            }
          );
        } else {
          this.setState(
            {
              page: 1,
            },
            () => {
              this.props.onFetchDataOptions(this.state.page, this.props.GroupBy);
              console.log('load_more_error', this.state.page);
            }
          );
        }
      };

      renderSeparator = () => {
        return (
          <View
            style={{
              height: 1,
              width: '100%',
              backgroundColor: '#CED0CE',
            }}
          />
        );
      };
      renderFooter = () => {
        if (!this.state.loading) return null;
        return (
          <View
            style={{
              paddingVertical: 20,
              borderTopWidth: 1,
              borderColor: '#CED0CE',
            }}>
            <ActivityIndicator animating size="large" />
          </View>
        );
      };

      renderRow = ({ item, index }) => {
        return (
          <View style={styles.ListContainer}>
            <View style={styles.Text}>
              <TextDetails Size={18}>{item.name}</TextDetails>
            </View>
          </View>
        );
      };
      render() {
        return (
          <View style={styles.SearchContatiner}>
            <View style={styles.Search}>
              <View style={styles.ImageIcon}>
                <Image
                  style={styles.Image}
                  resizeMode="contain"
                  source={require('../images/sokbla.png')}
                />
              </View>
              <View style={styles.InputBox}>
                <TextInput
                  style={styles.InputText}
                  onChangeText={text => this.setState({ query: text })}
                  placeholder={'Search for ' + this.props.Title}
                  value={this.state.query}
                />
              </View>
              <TouchableOpacity
                onPress={() => alert("remove query")}
                style={styles.KryssIcon}>
                <Image
                  style={styles.ImageKryss}
                  resizeMode="contain"
                  source={require('../images/kryssbla.png')}
                />
              </TouchableOpacity>
            </View>
            <View style={styles.Lista}>
              <FlatList
                style={styles.Flatlist}
                data={this.props.fetch_data_options}
                renderItem={this.renderRow}
                keyExtractor={item => item.name}
                ItemSeparatorComponent={this.renderSeparator}
                ListFooterComponent={this.renderFooter}
                onRefresh={this.handleRefresh}
                refreshing={this.state.refreshing}
                onEndReached={this.handleLoadMore}
                onEndReachedThreshold={0}
              />
            </View>
          </View>
        );
      }
    }
    const styles = StyleSheet.create({
      Lista: {
        marginTop: 20,
      },
      Flatlist: {
        width: '100%',
        height: 300,
      },
      ListContainer: {
        flexDirection: 'row',
        width: '100%',
        height: 40,
      },
      Text: {
        marginLeft: '10%',
        width: '70%',
        justifyContent: 'center',
      },
      SearchContatiner: {},
      Search: {
        width: '100%',
        height: 60,
        backgroundColor: 'rgb(240,240,240)',
        flexDirection: 'row',
      },
      Image: {
        width: 23,
        height: 33,
      },
      ImageIcon: {
        justifyContent: 'center',
        width: '15%',
        alignItems: 'center',
      },
      InputBox: {
        width: '70%',
        justifyContent: 'center',
      },
      InputText: {
        paddingLeft: 20,
        width: '100%',
        height: 50,
        fontSize: 20,
      },
      KryssIcon: {
        justifyContent: 'center',
        width: '15%',
        alignItems: 'center',
      },
      ImageKryss: {
        width: 18,
        height: 28,
      },
    });
    const mapStateToProps = state => {
      return {
        fetch_data_options: state.filter.fetch_data_options,
        fetch_data_error: state.filter.error,
        status: state.filter.status,

      };
    };
    const mapDispatchToProps = dispatch => {
      return {
        onFetchDataOptions: (page, group_by) =>
          dispatch(fetchDataOptions(page, group_by)),
        onResetDataOptions: () => dispatch(resetDataOptions()),

      };
    };
    export default connect(
      mapStateToProps,
      mapDispatchToProps
    )(Search);

Here is My Action

    import {
      FETCHING_DATA_OPTIONS,
      FETCH_DATA_OPTIONS_SUCCESS,
      FETCH_DATA_OPTIONS_FAILURE,
      FETCH_DATA_OPTIONS_RESET,
    } from './actionTypes';

    export const fetchDataOptions = (page, group_by) => {
      return dispatch => {
        dispatch(getDataOptions());
        return fetch(
          'https://ollenorstrom.se/ollenorstrom.se/avoka/api/getOptions.php?page=' +
            page +
            '&row_per_page=5&group_by=' +
            group_by
        )
          .then(res => res.json())
          .then(json => {
            //$json[0] containts .DATA, .STATUS, .MESSAGE
            //.STATUS can be 200 or 404, if its 404 it means that .DATA is empty              
            if (json[0].STATUS == 200) {
              return dispatch(
                getDataOptionsSuccess(json[0]),
                console.log('fetched_data', json[0])
              );
            } else {
              return dispatch(getDataOptionsFailure());
            }
          })
          .catch(err => dispatch(getDataOptionsFailure(err)));
      };
    };
    export const resetDataOptions = () => {
      return {
        type: FETCH_DATA_OPTIONS_RESET
      };
    };
    function getDataOptions() {
      return {
        type: FETCHING_DATA_OPTIONS,
      };
    }
    function getDataOptionsSuccess(data) {
      return {
        type: FETCH_DATA_OPTIONS_SUCCESS,
        data: data.DATA,
        status: data.STATUS
      };
    }
    function getDataOptionsFailure() {
      return {
        type: FETCH_DATA_OPTIONS_FAILURE,
      };
    }

回答1:


You haven't changed the value of refreshing state variable after dispatching the API call. It's set as true in your handleRefresh function but never set back to false.

Use one of the lifecycle methods componentWIllUpdate or componentDidUpdate to check whether the props have changed (API call success or fail), and change the state of your refreshing variable to false.

For eg. in your Search component add this,

componentDidUpdate(prevProps) {
  //Check whether props have changed and isFetching is false
  if (this.props.isFetching !== prevProps.isFetching && !this.props.isFetching) {
    this.setState({refreshing:false});
  }
}

Also check the value of onEndReachedThreshold is 0. Usage is explained here



来源:https://stackoverflow.com/questions/56204457/react-native-flatlist-gets-infinity-loop-onrefresh

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!