Redux - Deleting Item from State

Viewed 913

I am having issues deleting an item from state.

I have a container invoices, which displays a list of invoices rendered in InvoiceItem.

I am using mapStateToProps and an action/reducer to go off and fetch all invoices.

I then use mapDispatchToProps in the InvoiceItem, to dispatch an action on the delete button. (Only to remove from state, not DB).

Is this the correct usage of dealing with Redux actions (Connect)? I know from using React16's Context API, this is how I would approach things.

When debugging the mapDispatchToProps using console.log in the action and reducer files, the payload is coming through as UNDEFINED

Below is my code:

types.js

export const GET_INVOICES = "GET_INVOICES";
export const GET_INVOICE = "GET_INVOICE";
export const DELETE_INVOICE = "DELETE_INVOICE";
export const INVOICES_LOADING = "INVOICES_LOADING";

invoiceActions.js

import axios from "axios";
import { GET_INVOICES, DELETE_INVOICE, INVOICES_LOADING } from "./types";

// getInvoices is a large axios call that goes here. It works fine.
// Leaving it out in this example.

// Delete Invoice
export const deleteInvoice = invoice => dispatch => {
 console.log(invoice) // UNDEFINED
dispatch({
  type: DELETE_INVOICE,
  payload: invoice
});
};

// Invoices loading
export const setInvoicesLoading = () => {
 return {
  type: INVOICES_LOADING
 };
};

invoicesReducer.js

import {
 GET_INVOICES,
 DELETE_INVOICE,
 INVOICES_LOADING
 } from "../actions/types";

const initialState = {
invoices: [],
loading: false
};

 export default function(state = initialState, action) {
  switch (action.type) {
    case INVOICES_LOADING:
     return {
      ...state,
      loading: true
     };
   case GET_INVOICES:
     return {
     ...state,
     invoices: action.payload,
     loading: false
    };
   case DELETE_INVOICE:
    return invoices.filter(invoice => invoice.Id !== invoice);
    default:
    return state;
   }
  }

InvoiceItem.js

import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { deleteInvoice } from "../../actions/invoiceActions";

class InvoiceItem extends Component {
 onDeleteClick(e) {
 this.props.deleteInvoice();
 }
 render() {
  const { invoice } = this.props;

    return (
     <div className="card card-body bg-light mb-3">
       <div className="row">
         <div className="col-lg-6 col-md-4 col-8">
           <h3>Invoice: {invoice.InvoiceNumber}</h3>
           <p>Client: {invoice.Contact.Name}</p>
           <button
            onClick={this.onDeleteClick.bind(this)}
            className="btn btn-danger">
            Remove
           </button>
      </div>
    </div>
  </div>
  );
  }
 }

 InvoiceItem.propTypes = {
 invoice: PropTypes.object.isRequired,
 deleteInvoice: PropTypes.func
 };

 const mapDispatchToProps = dispatch => {
   return {
     deleteInvoice: invoice => dispatch(deleteInvoice(invoice))
    };
  };

  export default connect(
   mapDispatchToProps,
   { deleteInvoice }
  )(InvoiceItem);

Invoices.js

import React, { Component } from "react";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import Spinner from "../common/Spinner";
import InvoiceItem from "./InvoiceItem";
import { getInvoices } from "../../actions/invoiceActions";

class Invoices extends Component {
  componentDidMount() {
  this.props.getInvoices();
}

render() {
  const { invoices, loading } = this.props.invoice;
  let invoiceItems;

  if (invoices === null || loading) {
   invoiceItems = <Spinner />;
  } else {
  if (invoices.length > 0) {
    invoiceItems = invoices.map(invoice => (
      <InvoiceItem key={invoice.Id} invoice={invoice} />
    ));
  } else {
    invoiceItems = <h4>No invoices found...</h4>;
  }
}

return (
  <div className="profiles">
    <div className="container">
      <div className="row">
        <div className="col-md-12">
          <h1 className="display-4 text-center">Invoices</h1>
          {invoiceItems}
        </div>
      </div>
    </div>
  </div>
  );
 }
}

Invoices.propTypes = {
 getInvoices: PropTypes.func.isRequired,
 invoice: PropTypes.object.isRequired
};

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


export default connect(
 mapStateToProps,
 { getInvoices }
)(Invoices);
1 Answers

deleteInvoice is expecting invoice object to be passed in. As you are not passing anything in currently, it logs undefnied

onDeleteClick(e) {
   this.props.deleteInvoice(this.props.invoice);
}
Related