简体   繁体   English

带有 redux 工具包的 Redux:UI 没有改变

[英]Redux with redux toolkit: UI is not changing

I'm new to redux and redux toolkit in React.js.我是 React.js 中 redux 和 redux 工具包的新手。 Trying my best to make my PET project to apply for a future job, but faced a problem.尽我最大的努力让我的PET项目申请未来的工作,但遇到了一个问题。 I'll try to describe it.我会试着描述一下。

Firstly, the code.首先,代码。 removeInvoice function in invoice-slice.js file: invoice-slice.js 文件中的removeInvoice函数:

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: INVOICES_LIST看起来像这样:

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:我在其中映射发票的 AllInvoices.js文件:

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:还有我应该使用 removeInvoice的 Invoice.js文件:

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.它似乎从数组中删除了发票,因为数组从 3 个项目变为 2 个,并显示在控制台有效负载中,其中包含我想通过单击按钮删除的项目的适当 id,但这里的 UI console.log没有反映变化,仍然有 3 个发票项目,而不是 2 个或更少。 Anyone know what can be the problem?有谁知道可能是什么问题?

I've already tried alot of variants, like to pass an id to a function like this:我已经尝试了很多变体,比如将 id 传递给这样的函数:

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:我知道如果 UI 没有改变,那么状态就不会改变,但是,在我的情况下,我会像这样覆盖状态:

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:想到了 useSelector 并这样尝试:

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 .但它使页面崩溃并告诉我这个错误: Uncaught TypeError: invoice.map is not a function

So, i don't know what to do else.所以,我不知道还能做什么。 Please, help me!!!请帮我!!!

Ps I'm new in stackoveflow, so sorry if something wrong :) Ps 我是 stackoveflow 的新手,如果有问题,我很抱歉 :)

You aren't rerendering the INVOICE_LIST when it changes.当 INVOICE_LIST 更改时,您不会重新呈现它。 You would want to have a useEffect or something similar that will rerender the component when the INVOICE_LIST changes to see any changes on the UI side.您可能希望有一个 useEffect 或类似的东西,当 INVOICE_LIST 更改以查看 UI 端的任何更改时,它将重新呈现组件。

Your problem is this:你的问题是这样的:

{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,
                      }}
                    />
                  ))}

This is rendering static content and will not change even when you make a change to the redux store.这是呈现静态内容,即使您对 redux 存储进行更改也不会更改。 You need to change this to state that will rerender when it changes.您需要将其更改为在更改时将重新呈现的状态。

The problem is that you're using the constant INVOICE_LIST to map your elements instead of the current state of the store.问题是您使用常量 INVOICE_LIST 来映射您的元素而不是商店的当前状态。

You used INVOICE_LIST to initialize your slice, that's good.您使用 INVOICE_LIST 来初始化切片,这很好。 But then you did not use what you initialized, you simply used the constant, and that's why the UI remained constant.但是你没有使用你初始化的东西,你只是使用了常量,这就是 UI 保持不变的原因。

You should use useSelector to access that state like so:您应该使用 useSelector 来访问该状态,如下所示:

const invoiceList = useSelector(state => state.invoice.invoices)

This should be the correct syntaxe in your case:在您的情况下,这应该是正确的语法:

state.sliceName.wantedProperty

Now when you map on "invoiceList" instead of "INVOICE_LIST", this should do the trick!现在,当您映射到“invoiceList”而不是“INVOICE_LIST”时,这应该可以解决问题!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM