Реакция Redux отсутствует при проверке реквизита и рекомендуемый шаблон для инициализации контейнера из внешнего API с использованием redux-observable - PullRequest
0 голосов
/ 26 октября 2019

Я пытаюсь научиться использовать React с Redux в среде Typescript. Я использую шаблоны, предложенные на реагировать-редукс-машинопись площадка . Тем не менее, я получаю следующую ошибку при попытке создать код, указанный ниже:

«курсы» отсутствуют в проверке реквизитов

'courses.map' отсутствует в проверке реквизитов

Кто-нибудь еще сталкивался с таким типом ошибки? Это ошибка linting из плагина eslint: реагировать / рекомендуется?

Я также изо всех сил пытаюсь понять процесс инициализации состояния по умолчанию из хранилища с избыточностью при извлечении данных из API с использованием избыточного-наблюдаемого. У меня есть магазин, эпопеи, редукторы, действия и т. Д., Настроенные в соответствии с шаблонами с игровой площадки response-redux-typcript . Они сконфигурированы для получения списка курсов из API с использованием наблюдаемой редукции. Впоследствии у меня определены три действия и редукторы: 1. FETCH_COURSES_ERROR 2. FETCH_COURSES_REQUEST 3. FETCH_COURSES_SUCCESS

Как мне затем запустить мой контейнер CourseList для запуска процесса выборки и рендеринга списка курсов. Является ли хорошей практикой, чтобы хранилище с избыточностью получало начальное состояние для списка курсов (FETCH_COURSES_REQUEST -> FETCH_COURSES_SUCCESS || FETCH_COURSES_REQUEST -> FETCH_COURSES_ERROR. Короче говоря, я не понимаю, как подключить / вызвать эпическую часть к контейнеру CourseList ....

Epic Промежуточное программное обеспечение инициализировано и запущено в модуле магазина ....

import { RootAction, RootState, Services } from 'ReduxTypes';
import { Epic } from 'redux-observable';

import { isOfType } from 'typesafe-actions';

import { of } from 'rxjs';
import {
  catchError,
  filter,
  ignoreElements,
  map,
  switchMap,
} from 'rxjs/operators';

import { fetchCoursesFail, fetchCoursesSuccess } from './actions';

import constants from './constants';

export const fetchCoursesRequestAction: Epic<
  RootAction,
  RootAction,
  RootState,
  Services
> = (action$, state$, { courseServices }) =>
  action$.pipe(
    filter(isOfType(constants.FETCH_COURSES_REQUEST)),
    switchMap(action =>
      courseServices.default.getCourses().pipe(
        map(courses => fetchCoursesSuccess(courses)),
        catchError(error => of(fetchCoursesFail(error))),
      ),
    ),
    ignoreElements(), // ignore everything except complete and error, template does this
  );

CourseList

import React from 'react';

import Grid from '@material-ui/core/Grid';
import { GridSpacing } from '@material-ui/core/Grid';

import Course from '../../components/Course/Course';
import { Course as CourseModel } from '../../redux/features/course/model';

type Props = {
  courses: CourseModel[];
  // isLoading: boolean;
  // fetchCourses: any;
};

export const CourseList: React.FC<Props> = props => {
  const { courses } = props;

  return (
    <div style={{ marginTop: 20, padding: 30 }}>
      {
        <Grid container spacing={2 as GridSpacing} justify="center">
          {courses.map(element => (
            <Grid item key={element.courseID}>
              <Course course={element} />
            </Grid>
          ))}
        </Grid>
      }
    </div>
  );
};

CourseList - index.ts

import { RootState } from 'ReduxTypes';

import { connect } from 'react-redux';

import { CourseList } from './CourseList';
import { courseActions, courseSelectors } from '../../redux/features/course';

const mapDispatchToProps = {
  onFetchCoursesRequest: courseActions.fetchCoursesRequest,
};

const mapStateToProps = (state: RootState) => ({
  courses: courseSelectors.getReduxCourses(state.courses.fetchCoursesSuccess),
});

const CourseListConnected = connect(
  mapStateToProps,
  mapDispatchToProps,
)(CourseList);

export default CourseListConnected;

Приложение

import React, { Component, Suspense, lazy } from 'react';

import { BrowserRouter, Route, Switch } from 'react-router-dom';

import ErrorBoundary from '../errors/ErrorBoundary';
import { NavBar } from './NavBar/NavBar';

// code splitting at the route level
// lazy loading by route component, we could take this
// a step further and perform at component level
// React.lazy requires that the module export format for a component uses default
const About = lazy(() =>
  import(
    /*
  webpackChunkName: "about-page",
  webpackPrefetch: true
  */ '../views/About/About'
  ),
);

const CourseList = lazy(() =>
  import(
    /*
  webpackChunkName: "course-list",
  webpackPrefetch: true
  */ '../containers/CourseList'
  ),
);

const Home = lazy(() =>
  import(
    /*
webpackChunkName: "home-page",
webpackPrefetch: true
*/ '../views/Home/Home'
  ),
);

type AppProps = {};

export class App extends Component<AppProps, {}> {
  public render(): JSX.Element {
    return (
      <BrowserRouter>
        <div>
          <NavBar />
          <Suspense fallback={<div>LoaderOptionsPlugin...</div>}>
            <Switch>
              <Route path="/" component={Home} exact></Route>
              <Route path="/about" component={About}></Route>
              <Route
                path="/courses"
                render={(props): JSX.Element => (
                  <ErrorBoundary {...props}>
                    <CourseList />
                  </ErrorBoundary>
                )}
              ></Route>
              {/* <Route component={Error404}></Route> */}
            </Switch>
          </Suspense>
        </div>
      </BrowserRouter>
    );
  }
}

main.tsx

import React from 'react';
import { render } from 'react-dom';

import { App } from './app/components/App';

import { Provider } from 'react-redux';

import store from './app/redux/store';

const rootElement = document.getElementById('root');
render(
  <Provider store={store}>
    <App />
  </Provider>,
  rootElement,
);

Ответы [ 2 ]

0 голосов
/ 28 октября 2019

Получил это работает. Я использовал хук реакции useEffect , чтобы вызвать действие запроса для получения списка курсов. Когда функциональный компонент CourseList запускается, начальное состояние курсов пустое. Затем с помощью useEffect перехватывает действие fetchCoursesAsync.request , сопоставленное со свойством диспетчеризации fetchCourses .

fetchCoursesRequestAction epic затем выполняет вызов ajax и впоследствии запускает действие либо fetchCoursesSuccess , либо fetchCoursesFail .

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

import { RootState } from 'ReduxTypes';

type StateProps = {
  isLoading: boolean;
  courses: courseModels.Course[];
};

const dispatchProps = {
  fetchCourses: fetchCoursesAsync.request,
};

const mapStateToProps = (state: RootState): StateProps => ({
  isLoading: state.courses.isLoadingCourses,
  courses: courseSelectors.getReduxCourses(state.courses),
});

type Props = ReturnType<typeof mapStateToProps> & typeof dispatchProps;

const CourseList = ({
  courses = [],
  fetchCourses,
  isLoading,
}: Props): JSX.Element => {
  // fetch course action on mount
  useEffect(() => {
    fetchCourses();
  }, []);

  if (isLoading) {
    return <p>Loading...</p>;
  }

  return (
    <div style={{ marginTop: 20, padding: 30 }}>
      {
        <Grid container spacing={2 as GridSpacing} justify="center">
          {courses.map(element => (
            <Grid item key={element.courseID}>
              <Course course={element} />
            </Grid>
          ))}
        </Grid>
      }
    </div>
  );
};
0 голосов
/ 26 октября 2019

Отвечая на ваш первый вопрос: да, это ошибка eslint, вытекающая из правила react/prop-types, вы можете безопасно отключить его, нет необходимости в типах реквизита с машинописью.

Ваш второй вопрос, гдедолжна быть отправлена ​​вторая часть асинхронного действия? Это должно быть отправлено из вашего эпического наблюдаемого эпоса, а не из самого редукса и не из компонента контейнера реакции.

Документы с наблюдением за редуксом имеют простой пример обработки асинхронных действий при Real world example https://redux -observable.js.org / документы / основы / Epics.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...