Как предотвратить зависание пользовательского интерфейса при вызове API с помощью axios - PullRequest
0 голосов
/ 31 марта 2019

Я пытаюсь загрузить данные, когда мой компонент загружается с использованием componentDidMount.Однако, вызывая действие Redux, выполнение вызова с помощью axios, похоже, останавливает пользовательский интерфейс.Когда у меня есть форма с 12 входами, и один из них выполняет вызов API, я предполагаю, что могу ввести другие входные данные и не позволить им заморозить меня.

Я попытался прочитать другие посты на эту тему.но все они немного отличаются, и все, что я пробовал, похоже, не решает проблему.

Я работаю над Linux, используя React 16.8 (при использовании RN я использую 55.4)

IЯ пытался сделать мой componentDidMount асинхронный, а также действие приведения-редукции.Похоже, это ничего не помогло, поэтому я, должно быть, делал что-то не так.

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

async componentDidMount() {
    await getTasks().then();
}

И я попробовал это

export const getTasks = () => (async (dispatch, getState) => {
    return await axios.get(`${URL}`, AJAX_CONFIG).then();
}

Текущий код:

Component.js

componentDidMount() {
    const { userIntegrationSettings, getTasks } = this.props;
    // Sync our list of external API tasks
    if (!isEmpty(userIntegrationSettings)) {
        getTasks(userIntegrationSettings.token)
            // After we fetch our data from the API create a mapping we can use
            .then((tasks) => {
                Object.entries(tasks).forEach(([key, value]) => {
                    Object.assign(taskIdMapping, { [value.taskIdHuman]: key });
                });
            });
    }
}

Action.js

export const getTasks = () => ((dispatch, getState) => {
    const state = getState();
    const { token } = state.integrations;

    const URL = `${BASE_URL}/issues?fields=id,idReadable,summary,description`;
    const AJAX_CONFIG = getAjaxHeaders(token);

    dispatch(setIsFetchingTasks(true));

    return axios.get(`${URL}`, AJAX_CONFIG)
        .then((response) => {
            if (!isEmpty(response.data)) {
                response.data.forEach((task) => {
                    dispatch(addTask(task));
                });

                return response.data;
            } else {
                dispatch(setIsFetchingTasks(false));
            }
        })
        .catch((error) => {
            dispatch(setIsFetchingTasks(false));
            errorConsoleDump(error);
            errorHandler(error);
        });
});

reducer.js

export default (state = defaultState, action) => {
    switch (action.type) {
        case ADD_TASK:
        case UPDATE_TASK:
            return update(state, {
                byTaskId: { $merge: action.task },
                isFetching: { $set: false }
            });
        default:
            return state;
    }
};

Ответы [ 3 ]

1 голос
/ 11 апреля 2019

Итак, в моем ответе, что вы собираетесь изучать?

  • Общая загрузка данных с помощью Redux
  • Настройка метода жизненного цикла компонента, такого как componentDidMount()
  • Вызов создателя действия из componentDidMount()
  • Создатели действия запускают код для выполнения запроса API
  • API, отвечающий данными
  • Создатель действия возвращает action с выбраннымданные о свойстве payload

Итак, мы знаем, что есть два способа инициализации состояния в приложении Reactjs, мы можем либо вызвать функцию constructor(props), либо мы можем вызвать методы жизненного цикла компонента.В этом случае мы используем методы жизненного цикла компонентов, которые, как мы можем предположить, являются функциями на основе классов.

Вместо этого:

async componentDidMount() {
  await getTasks().then();
}

попробуйте это:

componentDidMount() {
  this.props.fetchTasks();
}

Таким образом, значение состояния создателей действий (fetchTasks ()) становится компонентами this.props.fetchTasks(); Таким образом, мы вызываем создателей действий из componentDidMount(), но не так, как вы это делали.

Асинхронная операция выполняется внутри вашего создателя действий, а не вашего componentDidMount() метода жизненного цикла.Цель вашего componentDidMount() метода жизненного цикла - запустить этого создателя действия в действие при загрузке приложения.

Таким образом, как правило, компоненты обычно отвечают за выборку данных посредством вызова создателя действия, но его создатель действияэто делает запрос API, так что там, где у вас происходит асинхронная JavaScript-операция, и там, где вы собираетесь реализовывать синтаксис ES7 async / await.

Другими словами, это не жизненный цикл компонента.метод, инициирующий процесс извлечения данных, который зависит от создателя действия.Метод жизненного цикла компонента просто вызывает создателя действия, который инициирует процесс извлечения данных, или асинхронный запрос.

Для ясности вы можете вызвать this.props.fetchTasks(); из вашего componentDidMount() метода жизненного цикла после того, какВы импортировали создатель действий в свой компонент, как и вы импортировали функцию подключения следующим образом:

import React from "react";
import { connect } from "react-redux";
import { fetchTasks } from "../actions";

Вы никогда не указывали имя компонента, в котором вы все это делаете, но в нижней части этого файла вынужно будет сделать export default connect(null, { fetchTasks })(ComponentName);

Я оставил первый аргумент как null, потому что вы должны передать mapStateToProps, но, поскольку я не знаю, есть ли у вас, вы можете просто передать nullна данный момент.

Вместо этого:

export const getTasks = () => (async (dispatch, getState) => {
    return await axios.get(`${URL}`, AJAX_CONFIG).then();
}

попробуйте это:

export const fetchTasks = () => async dispatch => {
  const response = await axios.get(`${URL}`, AJAX_CONFIG);
  dispatch({ type: "FETCH_TASKS", payload: response.data });
};

Нет необходимости определять getState в вашем создателе действий, если выне собираюсь использовать это.Вам также не хватало метода dispatch(), который необходим при разработке создателей асинхронных действий.Метод dispatch() собирается отправлять это действие и отправлять его всем различным редукторам в вашем приложении.

Здесь также вступает в игру промежуточное ПО, такое как Redux-Thunk, поскольку создатели действий не могут его обработать.Асинхронные запросы "из коробки".

Вы не показали, как вы подключили ваш Redux-Thunk, но обычно он идет в ваш корневой index.js файл и выглядит так:

import React from "react";
import ReactDOM from "react-dom";
import "./index.scss";
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";

import App from "./components/App";
import reducers from "./reducers";

const store = createStore(reducers, applyMiddleware(thunk));

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.querySelector("#root")

Помните ту функцию соединения, о которой я говорил, вам нужно было реализовать?Это возникло в результате реализации или вы должны были реализовать тег Provider.С тегом Provider все ваши компоненты могут иметь доступ к хранилищу Redux, но для того, чтобы подключить данные к вашим компонентам, вам необходимо импортировать функцию соединения.

Функция соединения - это то, что достигаетсявернитесь к Provider и сообщите ему, что он хочет получить доступ к этим данным внутри любого компонента, в котором используется этот метод жизненного цикла.

Redux-Thunk - это, безусловно, то, что вам нужно реализовать, если вы исправиливсе, как я предлагал выше.

Зачем нужен Redux-Thunk?

В нем нет ничего встроенного, это просто универсальное промежуточное ПО.Единственное, что он делает, - это позволяет нам обращаться с создателями действий, а это то, что вам нужно, чтобы он делал для вас.

Обычно создатель действия возвращает объект действия, но с помощью redux-thunk создатель действия может возвращать объект действия или функцию.

Если вы возвращаете объект действия, он все равно должен иметь typeсвойство, как вы видели в моем примере кода выше, и оно может дополнительно иметь свойство payload.

Redux-Thunk позволяет вам возвращать либо действие, либо функцию внутри создателя действия.

Но почему это важно?Кого волнует, возвращает ли он объект действия или функцию?Что это имеет значение?

Это возвращает нас к теме асинхронного JavaScript и того, как промежуточное ПО в Redux решает тот факт, что Redux не может обрабатывать асинхронный JavaScript из коробки.

Так что создатель синхронных действий мгновенно возвращает действие с готовыми данными.Однако, когда мы работаем с создателями асинхронных действий , как, например, в этом случае, ему требуется некоторое время, чтобы подготовить свои данные к работе.

Так что любой создатель действий, который делаетсетевой запрос квалифицируется как создатель асинхронных действий.

Сетевые запросы с JavaScript имеют асинхронный характер.

Таким образом, Redux-Thunk - это промежуточное ПО, представляющее собой функцию JavaScript, которая будет вызыватьсяс каждым действием, которое вы отправляете.Промежуточное программное обеспечение может мешать выполнению действия на ваши редукторы, изменять действие и т. Д.

0 голосов
/ 16 июля 2019

Я потратил часы на рефакторинг своего кода из обычной асинхронной / ожидания, чтобы использовать избыточный thunk, чтобы понять, что проблема действительно возникает на Deserializer

если у вас есть подобный код:

import { Deserializer } from 'jsonapi-serializer'

new Deserializer({ keyForAttribute: 'underscore_case' })
    .deserialize(response.data, deserialized => { 
      return deserialized 
})

Десериализатор всегда находится в режиме синхронизации, поэтому пользовательский интерфейс будет ждать, пока это не произойдет. завершено

Я не уверен, как сделать это асинхронно. Было бы здорово, если бы кто-нибудь мог мне сказать. Спасибо

0 голосов
/ 31 марта 2019

Вы устанавливаете dispatch(setIsFetchingTasks(true)), но когда axios возвращается, вы никогда не устанавливаете его в false. Вы пропустили добавление dispatch(setIsFetchingTasks(false)) до return response.data;? Это может быть причиной того, что ваш пользовательский интерфейс ожидает завершения fetchingTasks

...