首页 > 解决方案 > check if data has been loaded before passing as a prop react/redux

问题描述

I have an async/await api call that is made and the data is passed into my productsReducer, the problem I'm having is that the data is not loaded into the redux state when it is passed a prop into ProductsList and therefore throws an error when it tries to filter/map the data.

adding a check to see if it is loaded is possible in ProductsList products && products but I want to check on the Main component first if it is loaded and if so only pass this then as a prop.

I have attempted to do so with products: state.data.products.loadng === false && state.data.products.items.data but this always returns false

How can i check if my data is loaded before passing it as a prop?

Main.js

import React from 'react'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import { TransitionGroup, CSSTransition } from "react-transition-group";
import { connect } from "react-redux";
import styled from 'styled-components'
import ScrollToTop from '../atoms/ScrollToTop'
import Header from '../Header'
import Footer from '../Footer'
import Home from '../Home'
import * as actionCreators from './actions'
import media from '../atoms/Media'
import BreadCrumbs from '../Breadcrumbs'
import Category from '../Category'
import ProductsList from '../ProductsList'
import Product from '../Product'
import Alert from '../atoms/Alert'

import { fetchProducts } from "./actions";

import { ADD_TO_CART_E, ADD_TO_CART_P } from '../atoms/translations'    

class Main extends React.Component {

  componentDidMount() {
    this.props.fetchCategories()
    this.props.fetchSubCategories()
    this.props.fetchProducts()
  }

 handleHideAlert() {
    setTimeout(() => {
      this.props.hideAlert()
    }, 1000)
  }

  render() {
    const {alert, categories, filteredColors, filteredSizes, language, products,  showAlert, subCategories} = this.props
    const e = language === 'english'
    const p = language === 'polish'
    return(
      <Router>
        <Wrap>
        {alert && <div><Alert />{this.handleHideAlert()}</div>}
        <Header e={e} p={p} categories={categories} subCategories={subCategories} language={language} />
          {/* <BreadCrumbs /> */}
          <Route style={{ flex: 1 }} render={({ location }) =>
            <TransitionGroup>
              <CSSTransition
                key={location.key}
                timeout={500}
                classNames="page"
                mountOnEnter={true}
                unmountOnExit={true}
              >
                <Switch location={location}>
                  <MainWrap>
                  <Route exact path="/" render={props => <Home e={e} p={p} categories={categories} subCategories={subCategories} products={products} language={language} {...props} />} />
                  <Route exact path="/:catId" render={props => <Category e={e} p={p} categories={categories} subCategories={subCategories} language={language} {...props} />} />
                  <Route exact path="/:catId/:subCatId" render={props => <ProductsList  e={e} p={p} filteredColors={filteredColors} filteredSizes={filteredSizes} categories={categories} subCategories={subCategories} products={products} language={language} {...props} />} />
                  <Route exact path="/:catId/:subCatId/:productId" render={props => <Product categories={categories} subCategories={subCategories} products={products} showAlert={showAlert} language={language} {...props} />} />
                  </MainWrap>
                </Switch>
              </CSSTransition>
            </TransitionGroup>
          } />
          {console.log('products',products)}
  { e ? ADD_TO_CART_E : ADD_TO_CART_P}
          <Footer />
        </Wrap>
      </Router>
    )
  }
}

const mapStateToProps = state => ({
  alert: state.ui.alert,
  language: state.language,
  categories: state.data.categories.categories,
  subCategories: state.data.subCategories.subCategories,
  products: state.data.products.loadng === false && state.data.products.items.data 
  productsLoading: state.data.products.loadng,
  filteredColors: state.filters.colors,
  filteredSizes: state.filters.sizes
});

export default connect(mapStateToProps, actionCreators)(Main);

productsReducer.js

  import {
    FETCH_PRODUCTS_REQUEST,
    FETCH_PRODUCTS_SUCCESS,
    FETCH_PRODUCTS_FAILURE
  } from '../../Constants'

  const initialState = {
    items: [],
    loading: false,
    error: null
  };

  export default function productReducer(state = initialState, action) {
    switch(action.type) {
      case FETCH_PRODUCTS_REQUEST:
        return {
          ...state,
          loading: true,
          error: null
        };

      case FETCH_PRODUCTS_SUCCESS:
        return {
          ...state,
          loading: false,
          items: action.payload
        };

      case FETCH_PRODUCTS_FAILURE:
        return {
          ...state,
          loading: false,
          error: action.payload.error,
          items: []
        };

      default:
        return state;
    }
  }

productsList.js

class ProductsList extends React.Component {

  render() {
    const { e, p, filteredColors, filteredSizes,  match, products } = this.props
    const productFilter = products && products.filter(products =>
      (
        (filteredColors.length >= 1 && filteredSizes.length < 1 && products.cat === match.params.subCatId) && filteredColors.includes(products.color) ||
        (filteredSizes.length >= 1 && filteredColors.length < 1 && products.cat === match.params.subCatId) && filteredSizes.includes(products.size) ||

        (filteredSizes.length >= 1 && filteredColors.length >= 1 && products.cat === match.params.subCatId) && filteredColors.includes(products.color) && filteredSizes.includes(products.size)) ||
        (filteredSizes.length < 1 && filteredColors.length < 1 && products.cat === match.params.subCatId)
      )
    return(
      <Section>
        <Container>
          <Grid>
            {console.log(productFilter)}

            {productFilter && productFilter.map(filteredProduct =>
              <Cell key={filteredProduct.id}>
                <ProductListCard e={e} p={p} match={match} {...filteredProduct} />
              </Cell>
            )}
          </Grid>
        </Container>
        <Filters>
          <Filter />
        </Filters>
      </Section>
    )
  }
}

const mapStateToProps = state => ({
  filteredProducts: state.filteredProducts
});

export default connect(mapStateToProps, actionCreators)(ProductsList);

标签: javascriptreactjsredux

解决方案


您可以将初始状态设置为加载为真。在组件的构造函数或reducer中。在Main.js检查加载状态是否为真的渲染函数中,并确保渲染类似加载组件的内容。

加载数据时,将加载状态设置为 false。该页面将使用数据重新呈现和呈现列表。这足够了吗?或者你想要一个例子吗?


推荐阅读