React Native FlatList получает бесконечный цикл onRefresh - PullRequest
0 голосов
/ 19 мая 2019

Я пытаюсь извлечь данные из редукса в FlatList, а onRefresh = {} дает мне бесконечный цикл.Когда я не использую Redux, это работает, но когда я переместил процесс извлечения в Redux, я запутался.

Может кто-нибудь описать мне, что я делаю неправильно?

Заранее спасибо.

используй мою закуску: https://snack.expo.io/@thesvarta/redux-with-flatlist

Вот мой компонент

    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);

Вот мое действие

    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 Ответ

1 голос
/ 19 мая 2019

Вы не изменили значение переменной состояния refreshing после отправки вызова API. Он установлен как true в вашей функции handleRefresh, но никогда не устанавливается обратно на false.

Используйте один из методов жизненного цикла componentWIllUpdate или componentDidUpdate, чтобы проверить, изменились ли реквизиты (успешный или неудачный вызов API), и измените состояние переменной refreshing на false.

Например, в вашем компоненте поиска добавьте это,

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

Также проверьте, что значение onEndReachedThreshold равно 0. Объяснение использования здесь

...