Using Map Function in React on a Counter Function

Viewed 1294

I'm trying to use a counter that is being passed a prop that decrements by one for each iteration. It maps through a fake data service with key: value pairs. One of the pairs includes a property of count: 124. I keep getting this error however: "index.js:1 Warning: Failed prop type: Invalid prop keg of type array supplied to KegDetail, expected object."

Also, I want to implement a way that the counter cannot go negative.

Here is the masterKegList:

import { v4 } from 'uuid';

const masterKegList = [
  {
    id: v4(),
    name: 'Hefeweizen',
    brand: 'Widmer',
    price: '$140',
    alcohol: '5%',
    count: 1,
  },
  {
    id: v4(),
    name: 'A Little Sumpin Sumpin',
    brand: 'Lagunitas',
    price: '$160',
    alcohol: '7.5%',
    count: 124
  },
  {
    id: v4(),
    name: 'Chocolate Stout Nitro',
    brand: 'Rogue',
    price: '$220',
    alcohol: '5.8%',
    count: 124,
  },
  {
    id: v4(),
    name: 'Organic Dry Cider',
    brand: 'Avid Cider Co.',
    price: '$180',
    alcohol: '6%',
    count: 124
  },
  {
    id: v4(),
    name: 'Vienna Lager',
    brand: 'pFriem',
    price: '$155',
    alcohol: '5.3%',
    count: 124
  }
];

export function FakeKegList(){
    return masterKegList;
} 

Below is the main component that holds state.

import React from 'react';
import NewKegForm from '../NewKegForm/NewKegForm';
import KegList from "../KegList/KegList";
import KegDetail from "../KegDetail/KegDetail";
import EditKegForm from '../EditKegForm/EditKegForm';
import { FakeKegList } from '../../data/fakeKegService';
import './KegControl.css';
import hefImg from './img/hef.jpg';
import lagunitasImg from './img/lagunitas.jpg';
import rogueImg from './img/rogue.jpg';
import avidImg from './img/avid.jpeg';
import pfriemImg from './img/pfriem.png';
import tapGif from './img/tap.gif';
import pabstImg from './img/pabst.jpg';
import guinnessImg from './img/guinness.jpg';
import pacificoImg from './img/pacifico.jpg';
import Reveal from 'react-reveal/Reveal';
import Button from 'react-bootstrap/Button';


class KegControl extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      formVisibleOnPage: false,
      masterKegList: FakeKegList([]),
      selectedKeg: null,
      editing: false,
    };

  }

  handleClick = () => {
   if (this.state.selectedKeg != null) {
      this.setState({
        formVisibleOnPage: false,
        selectedKeg: null,
        editing: false
      });
    } else {
      this.setState(prevState => ({
        formVisibleOnPage: !prevState.formVisibleOnPage,
      }));
    }
  }

  handleAddingNewKegToList = (newKeg) => {
    const newMasterKegList = this.state.masterKegList.concat(newKeg);
    this.setState({masterKegList: newMasterKegList,
      formVisibleOnPage: false
    });
  }

  handleChangingSelectedKeg = (id) => {
    const selectedKeg = this.state.masterKegList.filter(keg => keg.id === id)[0];
    this.setState({selectedKeg: selectedKeg});
  }


handleEditClick = () => {
  this.setState({editing: true});
}

handleEditingKegInList = (kegToEdit) => {
  const editedMasterKegList = this.state.masterKegList
    .filter(keg => keg.id !== this.state.selectedKeg.id)
    .concat(kegToEdit);
  this.setState({
      masterKegList: editedMasterKegList,
      editing: false,
      selectedKeg: null
    });
}


handleDeletingKeg = (id) => {
  const newMasterKegList = this.state.masterKegList.filter(keg => keg.id !== id);
  this.setState({
    masterKegList: newMasterKegList,
    selectedKeg: null
  });
}

handleDecrementPint = () => {
  const sellPint = this.state.masterKegList.map((pint) => {
    if (pint.id !== this.state.selectedKeg.id) {
      return pint;
    }
    return {

      ...pint,
      count: pint.count - 1,
      // count: pint.count - 1 > 0
      // prevents count from going negative but doesn't work because count becomes a boolean value
    };
  });
  console.log(sellPint)
  // I tried setting selectedKeg to sellPint to keep user on keg detail page after selling pint, but then I get an error saying keg is an invalid prop type of "object". The number also goes away on keg detail page.
  this.setState({ masterKegList: sellPint, editing: false, formVisibleOnPage: true, selectedKeg: sellPint });
}



  render(){

    let currentlyVisibleState = null;
    let buttonText = null;

  if (this.state.editing ) {      
      currentlyVisibleState = <EditKegForm keg = {this.state.selectedKeg} onEditKeg = {this.handleEditingKegInList} onClickingDecrement = {this.handleDecrementPint} onClick={this.handleClick} />
      buttonText = "Return to Keg List"; 
    } else if (this.state.selectedKeg != null) {
      currentlyVisibleState = <KegDetail keg = {this.state.selectedKeg} onClickingDelete = {this.handleDeletingKeg} onClickingEdit = {this.handleEditClick} onClickingDecrement = {this.handleDecrementPint} />
      buttonText = "Return to Keg List";
    } else if (this.state.formVisibleOnPage) { 
      currentlyVisibleState = <NewKegForm onNewKegCreation={this.handleAddingNewKegToList} />;
    } else {
      currentlyVisibleState =
      <KegList kegList={this.state.masterKegList} onKegSelection={this.handleChangingSelectedKeg}/>;
      buttonText = "Add Keg";
    } 
    return (
      <React.Fragment>
      <Reveal>
      <div className="container">
        {currentlyVisibleState}
        <Button variant="primary" onClick={this.handleClick}>{buttonText}</Button>
      </div>
      </Reveal>
      <Reveal>
      <div className="row">
        <div className="column">
          <img alt="" src={lagunitasImg} />
          <img alt="" src={pfriemImg} />
          <img alt="" src={rogueImg} />
          <img alt="" src={tapGif} />
          <img alt="" src={hefImg} />
          <img alt="" src={avidImg} />
          <img alt="" src={tapGif} />
        </div>
        <div className="column">
          <img alt="" src={pabstImg} />
          <img alt="" src={guinnessImg} />
          <img alt="" src={lagunitasImg} />
          <img alt="" src={pacificoImg} />
          <img alt="" src={pfriemImg} />
          <img alt="" src={pabstImg} />
        </div>
        <div className="column">
          <img alt="" src={lagunitasImg} />
          <img alt="" src={pfriemImg} />
          <img alt="" src={rogueImg} />
          <img alt="" src={tapGif} />
          <img alt="" src={hefImg} />
          <img alt="" src={avidImg} />
          <img alt="" src={tapGif} />
        </div>
        <div className="column">
          <img alt="" src={pabstImg} />
          <img alt="" src={guinnessImg} />
          <img alt="" src={lagunitasImg} />
          <img alt="" src={pacificoImg} />
          <img alt="" src={pfriemImg} />
          <img alt="" src={pabstImg} />
        </div>
      </div>
      </Reveal>
      </React.Fragment>
    );
  }

}

export default KegControl;
1 Answers

Fix the count going negative:

count: Math.max(pint.count - 1, 0)

Addressing keg proptype

handleChangingSelectedKeg = (id) => {
  const selectedKeg = this.state.masterKegList.filter(keg => keg.id === id)[0];
  this.setState({selectedKeg: selectedKeg});
}

Array::filter returns an array, but you are popping the first element out to save in state, so it seems that this element is also an array if it is being passed to KegDetails on prop keg and it's expected to be an object (versus array). Please add what the shape of masterKegList is so we can help fix the proptype mismatch.

Related