FlatList переинициализируется с верхней части экрана при загрузке данных с использованием immer и redux saga - PullRequest
0 голосов
/ 27 июня 2019

На самом деле, я реализовал функцию встроенного реагирующего плоского списка onLoadMore.он прекрасно работает без сагов на избыточность или immer js, значит, когда я реализовал его с использованием локального состояния, он работал нормально.Но когда я пытаюсь использовать его с immer или redux saga, он отображает экран вверху после каждого вызова извлечения.

UI Component

class Test extends React.PureComponent {
   constructor(props){
       super(props);
       this._renderFooter = this._renderFooter.bind(this);
       this._handleLoadMore = this._handleLoadMore.bind(this);
   }

   componentDidMount(){
       const { from, to, onFetchRecipes} = this.props;

       return onFetchRecipes({from, to});
   }

   _handleLoadMore(){
       let { from, to, onFetchRecipes } = this.props;
       from = to;
       to = to + 10;
       return onFetchRecipes({from, to});
   }
   _renderFooter(){
       if (!this.props.recipes.loading) return null;
       return (
           <View
               style={{
                   position: 'relative',
                   width: width,
                   height: height,
                   paddingVertical: 20,
                   borderTopWidth: 1,
                   marginTop: 10,
                   marginBottom: 10,
                   borderColor: theme.PRIMARY_COLOR
               }}
           >
               <ActivityIndicator animating size="large" />
           </View>
       );
   };

   render(){
       const { recipes } = this.props;
       const itemList = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
       return (
           <FlatList
               style={{ marginBottom: 70, width: '100%'}}
               data={ !recipes.loading ? recipes.data.hits : []}
               renderItem={({ item }) =>
                   <CustomRow key={item.id} item={item}/>
               }
               keyExtractor={(item, index) => index.toString()}
               onEndReached={this._handleLoadMore}
               onEndReachedThreshold={0.5}
               ListFooterComponent={this._renderFooter}
               initialNumToRender={10}

           />
       );
   }
}

const mapStateToProps = state =>({
   to: makeSelectTo()(state),
   from: makeSelectFrom()(state),
   recipes: makeSelectRecipes()(state),
});

function mapDispatchToProps(dispatch) {
 return {
   onFetchRecipes: (params) => dispatch(fetchRecipes(params))
 };
}

const withConnect = connect(mapStateToProps, mapDispatchToProps);

const withReducer = injectReducer({ key: 'test', reducer });
const withSaga = injectSaga({ key: 'test', saga });

export default compose(
 withReducer,
 withSaga,
 withConnect,
)(Test);

Actions

import * as actions from './constants';

export function fetchRecipes(params) {
  return {
    type: actions.FETCH_RECIPE,
      params,
  };
}

export function fetchRecipesSuccess(payload) {
  return {
    type: actions.FETCH_RECIPE_SUCCESS,
    payload,
  };
}

Selector

import { createSelector } from 'reselect';
import { initialState } from './reducer';

/**
 * Direct selector to the test state domain
 */

const selectTestDomain = state => state.test || initialState;

/**
 * Other specific selectors
 */

/**
 * Default selector used by Test
 */


const makeSelectFrom = () =>
  createSelector(selectTestDomain, substate => substate.from);

const makeSelectTo = () =>
  createSelector(selectTestDomain, substate => substate.to);

const makeSelectRecipes = () =>
  createSelector(selectTestDomain, substate => substate.recipes);

export { makeSelectRecipes, makeSelectFrom, makeSelectTo };

Редуктор

import produce from 'immer';
import * as actions from './constants';

export const initialState = {
    to: 10,
    from: 0,
    recipes: {loading: false, data:{}}
};

const testReducer = (state = initialState, action) =>
  produce(state, (draft) => {
    switch (action.type) {
        case actions.FETCH_RECIPE:
            draft.recipes.loading = true;
            draft.from = action.params.from;
            draft.to = action.params.to;
        break;

        case actions.FETCH_RECIPE_SUCCESS:
            draft.recipes.loading = false;
            if(draft.recipes.data.hits && draft.recipes.data.hits.length > 0){
                draft.recipes.data.hits.push(...action.payload.hits);
            }else{
                draft.recipes.data = action.payload;
            }
        break;
    }
  });

export default testReducer;

Сага

import * as actions from './actions';
import * as constants from './constants';
import Request from '../../utils/NetworkManager';
import {takeLatest, all, put} from 'redux-saga/effects';

function* workerFetchRecipes(action) {
    try {
        const params = action.params;
        const response = yield Request.get('https://api.edamam.com/search', {params: {app_id: '4784637b', app_key: '12021eddf28af077a53a217fc81fc930', q:'chicken', from: params.from, to: params.to}});
        yield put(actions.fetchRecipesSuccess(response))

    } catch (error) {

    }
}

function* watchAll() {
    yield all([
        takeLatest(constants.FETCH_RECIPE, workerFetchRecipes),
    ]);
}

export default watchAll;
...