Слишком много повторных рендеров реагируют на редукцию после нажатия на текущей странице ссылки - PullRequest
0 голосов
/ 24 октября 2019

Я использую Redux с реагировать JS код работает нормально, но у меня проблема после нажатия на ссылку текущей страницы, я получаю сообщение об ошибке

Too many re-renders. React limits the number of renders to prevent an infinite loop.

Я пытаюсь решить эту проблему, но я не знаю, почему отправкаФункция выполняется после любого ответа на действие, как остановить рендеринг или заблокировать перенаправление, если ссылка равна текущей странице

Редуктор

const initState = {
    isFetching: false,
    isSuccess: false,
}

const tableReducer = (state = initState, action) => {
    switch (action.type) {

        case "GET_CONTENT_PENDING": {
            return {...state, isFetching: false, isSuccess: false,}
            break;
        }
        case "GET_CONTENT_REJECTED": {
            return {...state, error: action.payload, isFetching: false, isSuccess: false,}
            break;
        }
        case "GET_RESTORANT_FULFILLED": {
            return {
                ...state,
                isFetching: true,
                isSuccess: true,
                moreRestaurents: action.payload.moreRestaurents,
                restaurent: action.payload.details
            }
            break;
        }
        case "GET_CITIES_FULFILLED": {
            return {...state, isFetching: true, isSuccess: true, cities: action.payload.cities}
            break;
        }
        case "GET_RESTO_GROUP_BY_CITY_FULFILLED": {
            return {
                ...state,
                isFetching: true,
                isSuccess: true,
                restaurantsGroupedBySity: action.payload.restaurantsGroupedBySity
            }
            break;
        }
        case "GET_CITY_RESTORANTS_FULFILLED": {
            return {
                ...state,
                isFetching: true,
                isSuccess: true,
                cityRestaurents: action.payload.cityRestaurents,
                city: action.payload.city
            }
            break;
        }
        case "GET_MOST_RESERVED_FULFILLED": {
            return {
                ...state,
                isFetching: true,
                isSuccess: true,
                mostReservedRestaurents: action.payload.mostReservedRestaurents
            }
            break;
        }
        case "GET_TOP_RESTORANTS_FULFILLED": {
            return {...state, isFetching: true, isSuccess: true, topRestaurents: action.payload.topRestaurents}
            break;
        }
        case "GET_ALL_RESTORANTS_FULFILLED": {
            return {...state, isFetching: true, isSuccess: true, allRestaurents: action.payload.allRestaurents}
            break;
        }
        case "GET_CONTENT_FULFILLED": {
            return {
                ...state,
                isSuccess: true,
                isFetching: true,
                content: action.payload.content,
                page: action.payload.page
            }
            break;
        }
    }
    return state;
}
export default tableReducer;

Домашний компонент

export class Home extends Component {
    render() {
        var cities = this.props.homeState.cities;
        var content = this.props.homeState.content;
        var isSuccess = this.props.homeState.isSuccess;
        var isFetching = this.props.homeState.isFetching;
        var page = this.props.homeState.page == "/home";
        var restaurantsGroupedBySity = this.props.homeState.restaurantsGroupedBySity;

        if (isFetching && isSuccess && cities && content && restaurantsGroupedBySity && page) {
            var cities = this.props.homeState.cities;
            var content = this.props.homeState.content;
            var isSuccess = this.props.homeState.isSuccess;
            var isFetching = this.props.homeState.isFetching;
            var page = this.props.homeState.page == "/home";
            var restaurantsGroupedBySity = this.props.homeState.restaurantsGroupedBySity;

            if (isFetching && isSuccess && cities && content && restaurantsGroupedBySity && page) {
                return (
            } else {
                return (
                    <div className="loader">
                        <img src="/media/images/table-loader.svg" alt="" />
                    </div>
                )
            }
        }
    }
}

const mapStateToProps = (state) => {
    return {
        homeState: state
    }
}

const mapDispatchToProps = (dispatch, ownProps) => {
    return {
        getCities: getCities(dispatch),
        pageContent: pageContent(dispatch, ownProps.match.path),
        getRestaurantsGroupedByCity: getRestaurantsGroupedByCity(dispatch)
    };
}

export default connect(mapStateToProps, mapDispatchToProps)(Home)

Действия

import axios from 'axios';

export  const getCities =(dispatch)=> {
        let citiesQuery = '/api/get/cities';
        axios.all([
            axios.get(citiesQuery)
        ]).then(axios.spread((cities) => {
            return dispatch({ type: "GET_CITIES_FULFILLED", payload: { cities: cities.data}})
        })).catch (err => {
            return dispatch({ type: "GET_CONTENT_REJECTED", payload: err })
        }); 

        return dispatch({ type: "GET_CONTENT_PENDING"})
}
export const getRestaurantsGroupedByCity =(dispatch)=> {
        let restaurantsQuery = '/api/get/restaurants-group-by-city';
        axios.all([
            axios.get(restaurantsQuery),
        ]).then(axios.spread((response) => {
            return dispatch({ type: "GET_RESTO_GROUP_BY_CITY_FULFILLED", payload: { restaurantsGroupedBySity: response.data}})
        })).catch (err => {
            return dispatch({ type: "GET_CONTENT_REJECTED", payload: err })
        }); 

        return dispatch({ type: "GET_CONTENT_PENDING"})
}

1 Ответ

1 голос
/ 24 октября 2019

Я вижу две проблемы в вашем коде.

Первая - это синтаксическая ошибка в вашем Home компоненте:

// ...
if (isFetching && isSuccess && cities && content && restaurantsGroupedBySity && page) {
    // HERE IS SYNTAX ERROR, did you copy your code correctly?
    return (
} else {
// ...

Вторая - mapDispatchToProps, почему вы этого не сделалиэто согласно документации . Я не вижу ваших создателей действий, но обычно это должно быть примерно так:

const mapDispatchToProps = (dispatch, ownProps) => {
    return {
        getCities: (/* action creator args, if any */) =>
            dispatch(getCities(/* action creator args, if any */)),
        pageContent: (/* action creator args, if any */) =>
            dispatch(pageContent(/* action creator args, if any */)),
        getRestaurantsGroupedByCity: (/* action creator args, if any */) =>
            dispatch(getRestaurantsGroupedByCity(/* action creator args, if any */)),
    };
}

или, что еще лучше, не используйте mapDispatchToProps, просто вставьте объект во второй аргумент connect :

export default connect(
    mapStateToProps,
    {getCities, pageContent, getRestaurantsGroupedByCity}
)(Home)

РЕДАКТИРОВАТЬ (после добавления исходного кода создателей действий):

Поскольку вы используете создателей асинхронных действий, вы должны добавить redux-thunk (или redux-saga), но это проще для начинающих) промежуточное программное обеспечение для вашей конфигурации Redux. Затем вам следует переписать создателей действий следующим образом (см. Подробности в документации redux-thunk ):

import axios from 'axios';

export const getCities = () => (
    (dispatch) => {
        let citiesQuery = '/api/get/cities';
        axios.all([
            axios.get(citiesQuery)
        ]).then(axios.spread((cities) => {
            return dispatch({type: "GET_CITIES_FULFILLED", payload: {cities: cities.data}})
        })).catch(err => {
            return dispatch({type: "GET_CONTENT_REJECTED", payload: err})
        });

        return dispatch({type: "GET_CONTENT_PENDING"})
    }
)

export const getRestaurantsGroupedByCity = () => (
    (dispatch) => {
        let restaurantsQuery = '/api/get/restaurants-group-by-city';
        axios.all([
            axios.get(restaurantsQuery),
        ]).then(axios.spread((response) => {
            return dispatch({
                type: "GET_RESTO_GROUP_BY_CITY_FULFILLED",
                payload: {restaurantsGroupedBySity: response.data}
            })
        })).catch(err => {
            return dispatch({type: "GET_CONTENT_REJECTED", payload: err})
        });

        return dispatch({type: "GET_CONTENT_PENDING"})
    }
)

Улучшения читаемости:

Попробуйте использовать деструктуризацию объектов, ваш код будет более читабельным (и более коротким).

Home (верхняя часть)

Это:

var cities = this.props.homeState.cities;
var content = this.props.homeState.content;
var isSuccess = this.props.homeState.isSuccess;
var isFetching = this.props.homeState.isFetching;
var page = this.props.homeState.page == "/home";
var restaurantsGroupedBySity = this.props.homeState.restaurantsGroupedBySity;

if (isFetching && isSuccess && cities && content && restaurantsGroupedBySity && page) {
    var cities = this.props.homeState.cities;
    var content = this.props.homeState.content;
    var isSuccess = this.props.homeState.isSuccess;
    var isFetching = this.props.homeState.isFetching;
    var page = this.props.homeState.page == "/home";
    var restaurantsGroupedBySity = this.props.homeState.restaurantsGroupedBySity;

можно записатькак это:

const {homeState} = this.props;
const {cities, content, isSuccess, isFetching, page, restaurantsGroupedBySity} = homeState;
const isPage = page == "/home"; // I suggest to use '===' operator here

if (isFetching && isSuccess && cities && content && restaurantsGroupedBySity && isPage) {
    // you should not declare the same variables here again,
    // the whole this.props is readonly in whole component and will not change
    // (if so there is an error somewhere)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...