Примечание: я предполагаю, что у вас есть базовые знания о React и Redux, иначе эта статья вам не поможет

При запуске React я постоянно пытался выяснить, как лучше всего работать с API, пользовательским интерфейсом или базовой структурой проекта. Поработав некоторое время над этими вещами, я хотел поделиться лучшим подходом, который я нашел для себя (ваш пробег может быть другим).

В гипотетическом примере получения данных из API и отображения их в списке я бы сделал это так.

Шаг 1. Обработка запросов APIт.

1. API.js

Я начинаю с того, что сначала загружаю данные во внешний интерфейс. В любом компоненте я сохраняю файл api.js для обработки всех моих запросов для любого указанного компонента.

export const getParticipantList = url => {
    var participantList = api.Gget(url).then(response => {
      let metrics = {
         participantList: response.participant_lst,
         misc: response.misc
      };
      return metrics;
     });
    return participantList;
};

В приведенном выше примере я использую Ajax для обработки API. У меня есть модуль API для обработки всех запросов в проекте, и с помощью «windows.export» я могу использовать «api.Gget» в любом месте проекта с импортом этой функции. Вы можете использовать fetch API или любую другую библиотеку для обработки запросов API.

2. сага.js

Redux Saga — это библиотека промежуточного программного обеспечения, используемая для обработки хранилища данных и асинхронных задач. Вы также можете использовать редукционные преобразователи в зависимости от ваших требований.

мы будем использовать saga для обработки нашей асинхронной задачи, то есть нашего вызова API.

import { call, put, takeLatest } from 'redux-saga/effects';
import { 
FETCH_DASHBOARD_PARTICIPANTS_LIST_SUCCESS, FETCH_DASHBOARD_PARTICIPANTS_LIST_FAILURE, FETCH_DASHBOARD_PARTICIPANTS_LIST} from './constants';
import {getParticipantList} from './api'
function* fetchParticipantList(action) {
 try {
  const data = yield call(getParticipantList,url);
  yield put({ type: FETCH_DASHBOARD_PARTICIPANTS_LIST_SUCCESS, data: data })
} catch (e) {
yield put({ type: FETCH_DASHBOARD_PARTICIPANTS_LIST_FAILURE, message: e.message });
}
}
function* participantSaga() {
yield takeLatest(FETCH_DASHBOARD_PARTICIPANTS_LIST, fetchParticipantList);
}
export default participantSaga;

Saga работает с функциями генератора. Чтобы упростить понимание, рассмотрим два термина: слушатель и работник. Слушатель прослушивает каждое отправленное действие, чтобы оно соответствовало его типу. Если он поймает свой тип, он передаст рабочему процессу выполнение своего кода.

В нашем коде этим слушателем является participantSaga(). Он будет продолжать отслеживать, если тип: FETCH_DASHBOARD_PARTICIPANTS_LIST отправляется из действий. Если это так, он вызовет нашу рабочую функцию для ее выполнения. fetchParticipantList() в нашем случае является рабочим.

3. константы.js

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

export const FETCH_DASHBOARD_PARTICIPANTS_LIST="FETCH_DASHBOARD_PARTICIPANTS_LIST"
export const FETCH_DASHBOARD_PARTICIPANTS_LIST_SUCCESS="FETCH_DASHBOARD_PARTICIPANTS_LIST_SUCCESS"
export const FETCH_DASHBOARD_PARTICIPANTS_LIST_FAILURE="FETCH_DASHBOARD_PARTICIPANTS_LIST_FAILURE"

4. действия.js

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

export const fetchParticipantList = (params) =>{
  return (dispatch) =>{ dispatch({
       type: FETCH_DASHBOARD_PARTICIPANTS_LIST,
       action:params})
   }
}

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

5. редуктор.js

import { assign} from "lodash";
import{ FETCH_DASHBOARD_PARTICIPANTS_LIST_FAILURE,FETCH_DASHBOARD_PARTICIPANTS_LIST,FETCH_DASHBOARD_PARTICIPANTS_LIST_SUCCESS } from './constants';
const initialState = {
loading: false,
errorMessage:'',
participantList:[] }
export default (state=initialState, action) => {
 const {type} = action;
 switch(type) {
   case FETCH_DASHBOARD_PARTICIPANTS_LIST:
      return  assign({}, state, {loading: true})
   case FETCH_DASHBOARD_PARTICIPANTS_LIST_SUCCESS:
      return assign({}, state, {misc:action.data.misc, participantList: action.data.participantList,loading: false})
   case FETCH_DASHBOARD_PARTICIPANTS_LIST_FAILURE:
      return  assign({}, state, {errorMessage: action.message})
   default:
      return state;
   }
}

Редьюсер действует как глобальное хранилище данных. Когда мы получаем данные с сервера, мы сохраняем их в редюсере, чтобы к ним могли обращаться несколько компонентов.

Шаг 2. Компонент

Теперь наша база для получения данных и их хранения готова, теперь нам нужно показать данные и вызвать вызов API при монтировании компонента. Я использую материальный пользовательский интерфейс, который содержит множество готовых компонентов, что упрощает создание современного веб-сайта. В нашем примере index.js будет содержать этот компонент. Мы создадим простое представление списка, содержащее все элементы нашего списка.

import React, { Component} from "react";
import Typography from "@material-ui/core/Typography";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
const participants = props => {
return (
<Grid item xs={12} md={12}>
 <div>
  <List dense={true}>
   {props.participantList.map((elem, id) => {
     return (
      <ListItem>
        <ListItemIcon>
         <ListAltIcon />
        </ListItemIcon>
      <ListItemText
        secondary={
          <React.Fragment>
            {elem.name}
           <Typography
             variant="caption"
             display="block"
             gutterBottom
            >
             <strong>Filled on</strong>:{" "}
             {moment(elem.created_on).format("lll")}
            </Typography>
          <Typography variant="body2" gutterBottom>
             <strong>Value</strong>: {elem.id}
           </Typography>
      </React.Fragment>
     }></ListItemText>
    </ListItem>
    );
   })}
  </List>
 </div>
</Grid>
);
};
const mapStateToProps = ({ participants}) => {
const {
participantList
} = dashboardParticipants;
return {participantList}
export default connect(mapStateToProps)(participants);

ПРИМЕЧАНИЕ. В приведенном выше примере я использую как redux-thunk, так и redux-saga, поэтому мне не нужны mapDispatchToProps в компоненте.

Есть много способов сделать то, что я только что сделал, и некоторые из них могут быть даже лучше, но мы все учимся на наших усилиях и помогаем нашим сообществам. В следующей статье я покажу вам, как одновременно включить redux-saga и redux-thunk в наш проект.