Как контролировать флаг загрузки с помощью response-redux в том же компоненте? - PullRequest
0 голосов
/ 20 мая 2018

Я создаю проект с react-redux, в моем проекте много городов, щелкните каждый из городов, чтобы перейти к компоненту моего класса TheaterList.js

Я установил, что у моего редуктора есть флаг loading(по умолчанию true при успешном извлечении данных, затем вернуть их с false) с моим действием MOVIELIST_THEATER, вот мой код MovieListReducer.js:

import { 
  MOVIELIST_MAINACTIVITY, 
  MOVIELIST_THISWEEK,
  MOVIELIST_THEATER,
  MOVIELIST_TIME,
  MOVIE_DETAIL
} from '../actions/types';

const INITIAL_STATE = {
  mainMovie: [],
  thisWeek: [],
  theaterList: [],
  timeList: [],
  movieDetail: [],
  loading: true
};

export default (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case MOVIELIST_MAINACTIVITY:
      return {
        ...state,
        mainMovie: action.payload
      };
    case MOVIELIST_THISWEEK:
      return {
         ...state,
         thisWeek: action.payload
      };
    case MOVIELIST_THEATER:
      return {
         ...state,
         theaterList: action.payload,
         loading: false 
      };
    case MOVIELIST_TIME:
      return {
        ...state,
        timeList: action.payload
      };
    case MOVIE_DETAIL:
      return {
        ...state,
        movieDetail: action.payload
      };
    default:
      return state;
  }
};

А вот мой компонент класса TheaterList.js:

import React, { Component } from 'react';
import { View, Text, FlatList } from 'react-native';
import { ListItem } from 'react-native-elements';
import { connect } from 'react-redux';
import { fetchTheater } from '../actions';
import { Spinner } from './common';

class TheaterList extends Component {
  constructor(props) {
    super(props);
    this.renderItem = this.renderItem.bind(this);
    const { enCity } = this.props.navigation.state.params;
    this.state = { 
      navigation: this.props.navigation,
      enCity
    };
  }
  componentDidMount() {
    this.props.fetchTheater({ enCity: this.state.enCity });
  }

  renderItem({ item }) {
    // some view tag
  }

  render() {
    const theaters = this.props.theaterList;
    // the default is true when fetch data succeed then return it with false
    if (this.props.loading) {
      return (
        <Spinner text='Loading...' />
      );
    }
    return (
      <View style={{ flex: 1 }}>
        <FlatList
          data={theaters}
          renderItem={this.renderItem} 
          numColumns={1}
          horizontal={false}
          keyExtractor={(item, index) => index.toString()} 
        />
      </View>
    );
  }
}

const mapStateToProps = (state) => {
  const theaterList = state.listType.theaterList;
  const loading = state.listType.loading;

  return { theaterList, loading };
};

const styles = {
 // some style settings
};

export default connect(mapStateToProps, { fetchTheater })(TheaterList);

Сначала он работает очень хорошо, например, показывает, что <Spinner /> ждет, пока состояние возврата и повторного рендеринга данных покажет мой <FlatList />, но когда я вернусь к экрану иперейдите к TheaterList.js снова, я нахожу this.props.loading значение по-прежнему false.Это приводит к тому, что мой <Spinner /> не будет отображаться.

Я пытаюсь контролировать флаг загрузки, добавив this.props.loading = true; в функцию componentDidMount().Очевидно, что это неправильно.

Вот мой action.js:

import { 
  MOVIELIST_MAINACTIVITY, 
  MOVIELIST_THISWEEK,
  MOVIELIST_THEATER,
  MOVIELIST_TIME,
  MOVIE_DETAIL 
} from './types';

export const fetchMainMovieList = () => {
  return (dispatch) => {
    fetch('https://obscure-reaches-65656.herokuapp.com/api?city=Taipei&theater=Centuryasia')
      .then(response => response.json())
      .then(responseData => {
        dispatch({ type: MOVIELIST_MAINACTIVITY, payload: responseData[0].movie });
      })
      .catch((error) => console.log(error));
  };
};

export const fetchThisWeek = () => {
  return (dispatch) => {
    fetch('https://obscure-reaches-65656.herokuapp.com/api/thisWeek')
      .then(response => response.json())
      .then(responseData => {
        dispatch({ type: MOVIELIST_THISWEEK, payload: responseData[0].movie });
      })
      .catch((error) => console.log(error));    
  };
};

export const fetchTheater = ({ enCity }) => {
  return (dispatch) => {
    fetch(`https://obscure-reaches-65656.herokuapp.com/api/drivers?city=${enCity}&lng=121.584065&lat=25.041317`)
      .then(response => response.json())
      .then(responseData => {
        console.log(responseData);
        dispatch({ type: MOVIELIST_THEATER, payload: responseData });
      })
      .catch((error) => console.log(error));    
  };
};

export const fetchTime = ({ enCity, theater }) => {
  return (dispatch) => {
    fetch(`https://obscure-reaches-65656.herokuapp.com/api?city=${enCity}&theater=${theater}`)
      .then(response => response.json())
      .then(responseData => {
        dispatch({ type: MOVIELIST_TIME, payload: responseData[0].movie });
      })
      .catch((error) => console.log(error));    
  };
};

export const fetchDetail = ({ enCity, cnName }) => {
  return (dispatch) => {
    fetch(`https://obscure-reaches-65656.herokuapp.com/api/detail?city=${enCity}&movie=${cnName}`)
      .then(response => response.json())
      .then(responseData => {
        dispatch({ type: MOVIE_DETAIL, payload: responseData[0].movie });
      })
      .catch((error) => console.log(error));    
  };
};

Так как именно установить флаг loading с react-redux, если использовать тот же компонент класса?

Любая помощь будет оценена.Заранее спасибо.

В соответствии с рекомендациями @MRFrhn я внесу некоторые изменения.

В моем action.js добавьте dispatch({ type: MOVIE_REQUEST_THEATER }); перед извлечением данных:

export const fetchDetail = ({ enCity, cnName }) => {
  return (dispatch) => {
    dispatch({ type: MOVIE_REQUEST_THEATER });

    fetch(`https://obscure-reaches-65656.herokuapp.com/api/detail?city=${enCity}&movie=${cnName}`)
      .then(response => response.json())
      .then(responseData => {
        dispatch({ type: MOVIE_DETAIL, payload: responseData[0].movie });
      })
      .catch((error) => console.log(error));    
  };
};

ВМой редуктор добавляет регистр:

case MOVIE_REQUEST_THEATER:
  console.log('MOVIE_REQUEST_THEATER');
  return {
    ...state,
    loading: true, // show the spinner
  };

Я думаю, что это должно быть успешно, потому что я возвращаю loading flag true до получения данных, но это не работает, тогда я вижу свой журнал, console.log('MOVIE_REQUEST_THEATER');не показываетсяНе знаю почему ...

1 Ответ

0 голосов
/ 20 мая 2018

Когда вы в первый раз получаете свои данные, loading имеет значение true (из исходного состояния), а когда вы получаете ответ, вы устанавливаете его на false , но вы никогда не устанавливаете его снова на true, поэтомуэто будет ложью в следующий раз, когда вы это прочитаете.Вы должны установить его на true каждый раз, когда хотите получить.Вам также может понадобиться обрабатывать ошибки, например, когда ваш запрос терпит неудачу, поэтому для правильного способа реализовать это в приставке вам нужно 3 действия для вашего запроса:

  1. Действие, информирующее редукторычто запрос начался. Редукторы могут обработать это действие, переключив флаг isFetching (или loading в вашем коде) в состояние.Таким образом, пользовательский интерфейс знает, что пришло время показать счетчик.например, тип действия MOVIELIST_THEATER_REQUEST
  2. Действие, информирующее редукторов об успешном завершении запроса. Редукторы могут обработать это действие путем объединения новых данных в состояние, которым они управляют, и сброса isFetching,Пользовательский интерфейс будет скрывать счетчик и отображать извлеченные данные.например, тип действия MOVIELIST_THEATER_SUCCESS
  3. Действие, информирующее редукторы о том, что запрос не выполнен. Редукторы могут обработать это действие путем сброса isFetching.Кроме того, некоторые редукторы могут захотеть сохранить сообщение об ошибке, чтобы пользовательский интерфейс мог его отобразить.например, тип действия MOVIELIST_THEATER_FAILURE

Таким образом, ваш редуктор будет выглядеть примерно так:

case MOVIELIST_THEATER_REQUEST:
  return {
     ...state,
     loading: true, // this will show the spinner
     error: false
};

case MOVIELIST_THEATER_SUCCESS:
  return {
     ...state,
     theaterList: action.payload,
     loading: false,
     error: false
};

case MOVIELIST_THEATER_FAILURE:
  return {
     ...state,
     loading: false,
     error: true
};

...

Считайте это для получения более подробной информации.

============

Обновление:

Измените свое действие на:

export const fetchDetail = ({ enCity, cnName }) => {
   return (dispatch) => {
      dispatch(request_theater());

       fetch(`https://obscure-reaches-65656.herokuapp.com/api/detail?city=${enCity}&movie=${cnName}`)
        .then(response => response.json())
        .then(responseData => {
            dispatch({ type: MOVIE_DETAIL, payload: responseData[0].movie });
            })
        .catch((error) => console.log(error));    
   };
};

export function request_theater() {
    return {
        type: MOVIE_REQUEST_THEATER
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...