MoreeZ
MoreeZ

Reputation: 118

mapStateToProps state returns 'undefined' two times before fetching the data from firebase

Component doesn't retrieve data from Firebase before it mounts.

const mapStateToProps = (state, ownProps) => {
  return {
    products: state.firestore.ordered.products
  };
};

when I test for the props after it mounts...

componentDidMount() {
    console.log(this.props);
}

The value of this.props.product is undefined.


If I console.log the state parameter inside mapStateToProps() I immediately get two console.logs of undefined and after a short while, I receive the actual array that I wanted.

const mapStateToProps = (state, ownProps) => {
  const products2 = state.firestore.ordered.products;

  console.log(products2);  //returns 2 console logs of undefined,
  // after a second (after the component mounts) it gives me the data

  return {
    products: state.firestore.ordered.products
  };
};

The reason why that is an issue is when I want to render the component using the data from the Firebase.

<div className="item-render-space">
          {products
            .filter(
              eachProduct =>
                eachProduct.landingPageCategory.indexOf(this.props.category) >
                -1
            )
            .map(eachProduct => (
              <div className="each-product" key={eachProduct.id}>
                <Link to={"/product/" + eachProduct.id}>
                  <img src={eachProduct.image} alt="#" />
                  <p className="product-price">{eachProduct.price}</p>
                  <p className="product-name">
                    {nameShortener(eachProduct.name)}
                  </p>
                </Link>
              </div>
            ))}
        </div>

I get an error screen because the variable "products" is undefined because The data from the firebase hasn't reached the component when it started rendering.

How to fix this issue?!

EDIT: Here is the rootReducer:

const rootReducer = combineReducers({
  firestore: firestoreReducer, //connects to firestore
  live: liveReducer, //used locally for opening bootstrap modals
  products: productsReducer, //previous products store before implementing Firestore
  firebase: firebaseReducer //connects to firebase
});

Upvotes: 1

Views: 283

Answers (1)

Alexander Staroselsky
Alexander Staroselsky

Reputation: 38807

Try using conditional rendering to avoid attempting to execute Array.prototype.filter() and Array.prototype.map() on undefined. The following would check for products to be truthy and have a length of greater than 0:

<div className="item-render-space">
  {products && products.length > 0 && products
    .filter(
      eachProduct =>
        eachProduct.landingPageCategory.indexOf(this.props.category) >
        -1
    )
    .map(eachProduct => (
      <div className="each-product" key={eachProduct.id}>
        <Link to={"/product/" + eachProduct.id}>
          <img src={eachProduct.image} alt="#" />
          <p className="product-price">{eachProduct.price}</p>
          <p className="product-name">
            {nameShortener(eachProduct.name)}
          </p>
        </Link>
      </div>
    ))}
</div>

Hopefully that helps!

Upvotes: 1

Related Questions