Как отобразить массив в список с помощью Reactjs Redux-Saga

Здравствуйте, в эти несколько дней я пытаюсь отобразить список продуктов с помощью redux-saga. В качестве структуры я использую шаблон реакции. У меня есть два компонента ProductsList и ProductsItem:

ProductsList.js

function ProductsList({ loading, error, products }) {
  if (loading) {
    return <List component = {LoadingIndicator} />;
  }

  if (error !== false) {
    const ErrorComponent = () => (
      <ListItem item = "Something went wrong, please try again!" />
    );
    return <List component = {ErrorComponent} />;
  }

  if (products !== false) {
    return <List items = {products} component = {Products} />;
  }

  return null;
}

ProductsList.propTypes = {
  loading: PropTypes.bool,
  error: PropTypes.any,
  products: PropTypes.any,
};

export default ProductsList;

Products.js:

function Products(props) {
  return (
    <div className = "contact">
      <span>{props.title}</span>
    </div>
  );
}

Products.propTypes = {
  title: PropTypes.string.isRequired
};

List.js

function List(props) {
      const ComponentToRender = props.component;
      let content = <div />;

      // If we have items, render them
      if (props.items) {
        content = props.items.map(item => (
          <ComponentToRender key = {`item-${item.id}`} item = {item} />
        ));
      } else {
        // Otherwise render a single component
        content = <ComponentToRender />;
      }

      return (
        <Wrapper>
          <Ul>{content}</Ul>
        </Wrapper>
      );
    }

    List.propTypes = {
      component: PropTypes.func.isRequired,
      items: PropTypes.array,
    };

Контейнер моей главной страницы вызывает действие с функцией ComponentDidMount (там работает Everyting, я его отлаживал). Но, возможно, что-то не так с отрисовкой прототипа муравья.

MainPage.js

class MainPage extends React.Component {
  componentDidMount() {
    this.props.onFetch();
  }

  render() {
    const { error, loading, products } = this.props;

        const reposListProps = {
          loading,
          error,
          products,
        };

    return (
         <article>
            <Helmet>
              <title>Products</title>
              <meta
                name = "description"
                content = "A React.js Boilerplate application products"
              />
            </Helmet>
            <div>
                <ProductsList {...reposListProps} />
            </div>
          </article>
        );
      }
    }

PostedCasesClient.propTypes = {
  loading: PropTypes.bool,
  error: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
  products: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),
  onFetch: PropTypes.func
};


export function mapDispatchToProps(dispatch) {
  return {
    onFetch: evt => {
      dispatch(fetchProducts());
    },
  };
}

const mapStateToProps = createStructuredSelector({
  mainPage: makeSelectPostedCasesClient
});

const withConnect = connect(
  mapStateToProps,
  mapDispatchToProps,
);

const withReducer = injectReducer ({ключ: 'основной', редуктор}); const withSaga = injectSaga ({ключ: 'главная', сага});

экспорт по умолчанию составить ( withReducer, withSaga, withConnect, )(Главная страница);

Позже, после отправки действия fetchProduct, я использую саги. Эта часть также работает, потому что я передаю свой массив продуктов редуктору.

Saga.js

export function* getProducts() {
  try {

  let requestURL = 'http://localhost:8080/produts';

  const products = yield call(request, requestURL, { method: 'GET' });

      yield put(fetchProductSuccess(products));

  } catch (error) {
    yield put(type: 'FETCH_PRODUCTS_FAILURE', error)
    console.info(error);
  }
}
export default function* actionWatcher() {
     yield takeLatest(FETCH_PRODUCTS_BEGIN, getProducts)
}

reducer.js

const initialState = fromJS({
  loading: false,
  error: false,
  items: false
});

function ProductsReducer(state = initialState, action) {
  switch(action.type) {
    case FETCH_PRODUCTS_BEGIN:
      return state
        .set('loading', true)
        .set('error', false)
        .setIn('items', false);
    case FETCH_PRODUCTS_SUCCESS:
      return state
        .setIn('items', action.products)
        .set('loading', false)
    case FETCH_PRODUCTS_FAILURE:
      return state.set('error', action.error).set('loading', false);
    default:
      return state;
  }
}

Может кто подскажет, что я делаю не так? Если вам нужно больше кода, скажите, я его отредактирую.

Обновлено:

Вот мой селектор:

const selectGlobal = state => state.get('global');

const makeSelectMainClient = () =>
  createSelector(selectMainPageDomain, substate => substate.toJS());

  const makeSelectLoading = () =>
    createSelector(selectGlobal, globalState => globalState.get('loading'));

  const makeSelectError = () =>
    createSelector(selectGlobal, globalState => globalState.get('error'));

  const makeSelectProducts = () =>
    createSelector(selectGlobal, globalState =>
      globalState.getIn(['products']),
    );

export default makeSelectPostedCasesClient;
export {
selectMainPageDomain,
  selectGlobal,
  makeSelectLoading,
  makeSelectError,
  makeSelectProducts,
};

🤔 А знаете ли вы, что...
React подходит для разработки как небольших веб-сайтов, так и крупных приложений.


903
1

Ответ:

Вам необходимо обновить функцию mapStateToProps, подключив компонент MainPage, чтобы получать данные в ваших новых редукторах. В настоящее время у вас есть:

const mapStateToProps = createStructuredSelector({
  mainPage: makeSelectPostedCasesClient
});

Однако ваш компонент ожидает получить loading, error и products. Вам нужно будет создать функцию mapStateToProps, которая предоставляет эти переменные вашему компоненту. Что-то типа:

const mapStateToProps = createStructuredSelector({
  products: makeSelectProducts(),
  loading: makeSelectLoading(),
  error: makeSelectError(),
});

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