I'm new to redux and redux toolkit in React.js. Trying my best to make my PET project to apply for a future job, but faced a problem. I'll try to describe it.
Firstly, the code. removeInvoice function in invoice-slice.js file:
import { createSlice } from "@reduxjs/toolkit";
import { INVOICES_LIST } from "../Pages/Invoice/InvoicesList";
const invoiceSlice = createSlice({
name: "invoice",
initialState: {
invoices: INVOICES_LIST,
},
reducers: {
addNewInvoice(state, action) {
const newItem = action.payload;
state.invoices.push({
id: newItem.id,
billFrom: newItem.bill_from,
billFromAddress: newItem.billFromAddress,
billTo: newItem.bill_to,
billToAddress: newItem.bill_to_address,
invoiceNumber: newItem.invoice_num,
});
console.log(newItem);
},
removeInvoice(state, action) {
const id = action.payload;
state.invoices = state.invoices.filter((item) => item.id !== id);
console.log(action);
console.log(state.invoices);
},
editInvoice() {},
},
});
export const invoiceActions = invoiceSlice.actions;
export default invoiceSlice;
INVOICES_LIST looks like this:
export const INVOICES_LIST = [
{
id: Math.random().toString(),
number: Math.random().toFixed(2),
invoice_num: "#1232",
bill_from: "Pineapple Inc.",
bill_to: "REDQ Inc.",
total_cost: "14630",
status: "Pending",
order_date: "February 17th 2018",
bill_from_email: "pineapple@company.com",
bill_from_address: "86781 547th Ave, Osmond, NE, 68765",
bill_from_phone: "+(402) 748-3970",
bill_from_fax: "",
bill_to_email: "redq@company.com",
bill_to_address: "405 Mulberry Rd, Mc Grady, NC, 28649",
bill_to_phone: "+(740) 927-9284",
bill_to_fax: "+0(863) 228-7064",
ITEMS: {
item_name: "A box of happiness",
unit_costs: "200",
unit: "14",
price: "2800",
sub_total: "133300",
vat: "13300",
grand_total: "14630",
},
},
{
id: Math.random().toString(),
number: Math.random().toFixed(2),
invoice_num: "#1232",
bill_from: "AMD Inc.",
bill_to: "Intel Inc.",
total_cost: "14630",
status: "Delivered",
order_date: "February 17th 2018",
bill_from_email: "pineapple@company.com",
bill_from_address: "86781 547th Ave, Osmond, NE, 68765",
bill_from_phone: "+(402) 748-3970",
bill_from_fax: "",
bill_to_email: "redq@company.com",
bill_to_address: "405 Mulberry Rd, Mc Grady, NC, 28649",
bill_to_phone: "+(740) 927-9284",
bill_to_fax: "+0(863) 228-7064",
ITEMS: {
item_name: "Unicorn Tears",
unit_costs: "500",
unit: "14",
price: "1700",
sub_total: "133300",
vat: "13300",
grand_total: "14630",
},
},
{
id: Math.random().toString(),
number: Math.random().toFixed(2),
invoice_num: "#1232",
bill_from: "Apple Inc.",
bill_to: "Samsung",
total_cost: "14630",
status: "Shipped",
order_date: "February 17th 2018",
bill_from_email: "pineapple@company.com",
bill_from_address: "86781 547th Ave, Osmond, NE, 68765",
bill_from_phone: "+(402) 748-3970",
bill_from_fax: "",
bill_to_email: "redq@company.com",
bill_to_address: "405 Mulberry Rd, Mc Grady, NC, 28649",
bill_to_phone: "+(740) 927-9284",
bill_to_fax: "+0(863) 228-7064",
ITEMS: {
item_name: "Rainbow Machine",
unit_costs: "700",
unit: "5",
price: "3500",
sub_total: "133300",
vat: "13300",
grand_total: "14630",
},
},
];
AllInvoices.js file where i map invoices:
import React, { Fragment } from "react";
import { useDispatch, useSelector } from "react-redux";
import { uiActions } from "../../store/ui-slice";
// import { invoiceActions } from "../../store/invoice-slice";
import { INVOICES_LIST } from "../Invoice/InvoicesList";
import Wrapper from "../../UI/Wrapper";
import Card from "../../UI/Card";
import Footer from "../../UI/Footer";
import Button from "../../UI/Button";
// import InvoiceItemDescription from "./InvoiceItemDescription";
// import EditInvoiceItem from "./EditInvoiceItem";
import classes from "./AllInvoices.module.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChevronDown } from "@fortawesome/free-solid-svg-icons";
// import AddInvoiceItem from "./AddInvoiceItem";
import { Link } from "react-router-dom";
import Invoice from "./Invoice";
const AllInvoices = (props) => {
// const { id } = props;
const dispatch = useDispatch();
const toggleSelectOptions = () => {
dispatch(uiActions.toggleSelectOptions());
};
// const removeInvoiceItem = (id) => {
// dispatch(invoiceActions.removeInvoice(id));
// };
const showMoreOptions = useSelector(
(state) => state.ui.selectOptionsIsVisible
);
// const invoice = useSelector((state) => state.invoices);
return (
<Fragment>
<Wrapper isShrinked={props.isShrinked}>
<Card>
<h1 className={classes.header}>Invoice</h1>
<div className={classes.content}>
<div className={classes["btn-wrapper"]}>
<Link to="/invoices/add-invoice">
<Button>Add Invoice</Button>
</Link>
</div>
<div className={classes.invoices}>
{showMoreOptions && (
<ul className={classes.list}>
<li>Select all invoices</li>
<li>Unselect all</li>
<li>Delete selected</li>
</ul>
)}
<table>
<colgroup>
<col className={classes.col1}></col>
<col className={classes.col2}></col>
<col className={classes.col3}></col>
<col className={classes.col4}></col>
<col className={classes.col5}></col>
<col className={classes.col6}></col>
<col className={classes.col7}></col>
</colgroup>
<thead className={classes["table-head"]}>
<tr>
<th className={classes.position}>
<span className={classes.checkbox}>
<input type="checkbox"></input>
</span>
<FontAwesomeIcon
icon={faChevronDown}
className={classes.chevron}
onClick={toggleSelectOptions}
/>
</th>
<th>
<span className={classes["thead-text"]}>Number</span>
</th>
<th>
<span className={classes["thead-text"]}>Bill From</span>
</th>
<th>
<span className={classes["thead-text"]}>Bill To</span>
</th>
<th>
<span className={classes["thead-text"]}>Total Cost</span>
</th>
<th>
<span className={classes["thead-text"]}>Status</span>
</th>
</tr>
</thead>
<tbody>
{INVOICES_LIST.map((invoice, index) => (
<Invoice
key={index}
invoiceItem={{
id: invoice.id,
invoice_num: invoice.invoice_num,
bill_from: invoice.bill_from,
bill_to: invoice.bill_to,
status: invoice.status,
}}
/>
))}
</tbody>
</table>
</div>
</div>
</Card>
<Footer />
</Wrapper>
</Fragment>
);
};
export default AllInvoices;
And Invoice.js file where i should use removeInvoice:
import React from "react";
import classes from "./Invoice.module.css";
import { useDispatch } from "react-redux";
import { Link } from "react-router-dom";
import { invoiceActions } from "../../store/invoice-slice";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faTrash } from "@fortawesome/free-solid-svg-icons";
const Invoice = (props) => {
const { id, invoice_num, bill_from, bill_to, status } = props.invoiceItem;
const dispatch = useDispatch();
const removeInvoiceItem = () => {
dispatch(invoiceActions.removeInvoice(id));
};
return (
<tr className={classes.height}>
<td>
<span className={classes.checkbox}>
<input type="checkbox"></input>
</span>
</td>
<td>
<span>{invoice_num}</span>
</td>
<td>
<span>{bill_from}</span>
</td>
<td>
<span>{bill_to}</span>
</td>
<td>
<span>14300</span>
{/* This should be a dynamic value later */}
</td>
<td>
<span
className={`${
status === "Pending" ? classes["status-pending"] : ""
} ${status === "Delivered" ? classes["status-delivered"] : ""} ${
status === "Shipped" ? classes["status-shipped"] : ""
}`}
>
{status}
</span>
</td>
<td>
<div className={classes.buttons}>
<Link to={`/invoices/invoice-description/${id}`}>
<button className={classes["view-btn"]}>View</button>
</Link>
<button className={classes["delete-btn"]} onClick={removeInvoiceItem}>
<FontAwesomeIcon icon={faTrash} />
</button>
</div>
</td>
</tr>
);
};
export default Invoice;
Now, the issue. It seems to remove the invoice from an array, because array changes from 3 items to 2, and shows in a console payload with appropriate id of item which i wanted to remove by clicking on a button, but UI console.log here doesn't reflect the changes, there is still 3 invoice items instead of 2 or less. Anyone know what can be the problem?
I've already tried alot of variants, like to pass an id to a function like this:
const removeInvoiceItem = (id) => {
dispatch(invoiceActions.removeInvoice(id));
};
Tried to make it with curly braces:
const removeInvoiceItem = (id) => {
dispatch(invoiceActions.removeInvoice({ id }));
};
Also tried anonymous function here:
<button className={classes["delete-btn"]} onClick={() => removeInvoiceItem(id)}>
<FontAwesomeIcon icon={faTrash} />
</button>
And so on. I know that if UI doesn't change, then state is not changing, but, in my case, i overwrite the state like this:
state.invoices = state.invoices.filter((item) => item.id !== id);
So, i don't know what else to do. Thought of useSelector and tried it like this:
const invoice = useSelector((state) => state.invoices);
And in map function:
{invoice.map((invoice, index) => (
<Invoice
key={index}
invoiceItem={{
id: invoice.id,
invoice_num: invoice.invoice_num,
bill_from: invoice.bill_from,
bill_to: invoice.bill_to,
status: invoice.status,
}}
/>
))}
But it was crashing the page and telling me this error: Uncaught TypeError: invoice.map is not a function.
So, i don't know what to do else. Please, help me!!!
P.s. I'm new in stackoveflow, so sorry if something wrong :)