在将状态传递给 Link 组件后,导航会导致状态发生变化

navigating results in changes of state in react after passing state to Link component

我正在用 React 制作一个购买发票应用程序。

应用程序中现在有两个页面。
一个是创建新发票的页面,可以将其保存到数据库并导出到 excel 文件。 (Invoice.js)
另一个是发票列表的页面,每个发票都有 modify/delete 按钮。 (Invoices.js)

当点击列表修改按钮中的发票时,它link进入创建页面,作为状态的发票数据作为参数传递。

没有将发票数据传递到创建页面,导航完全没有问题。
但是,我把'state'属性放到Link组件后,出现如下错误

Invoices.js:21
Uncaught TypeError: Cannot read properties of undefined (reading 'substring')
at Invoices.js:21:1
at Array.filter ()
at Invoices.js:21:1
at invokePassiveEffectCreate (react-dom.development.js:23487:1)
at HTMLUnknownElement.callCallback (react-dom.development.js:3945:1)
at Object.invokeGuardedCallbackDev (react-dom.development.js:3994:1)
at invokeGuardedCallback (react-dom.development.js:4056:1)
at flushPassiveEffectsImpl (react-dom.development.js:23574:1)
at unstable_runWithPriority (scheduler.development.js:468:1)
at runWithPriority (react-dom.development.js:11276:1)

这是我的源代码

// App.js

const App = () => {
  return (
    <BrowserRouter>
      <Container maxWidth="lg">
        <NavBar />
        <Routes>
          <Route path="/" exact element={<Navigate to="/invoice/create" />} />
          <Route path="/invoice/create" element={<Invoice />} />
          <Route path="/invoice/view" element={<Invoices />} />
        </Routes>
      </Container>
    </BrowserRouter>
  );
};

// Invoices.js

import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getInvoices } from '../../actions/invoices';
import InvoiceRow from './InvoiceRow';

const Invoices = () => {
  const [month, setMonth] = React.useState(new Date().getMonth() + 1);

  const invoices = useSelector((state) => state.invoices);
  const dispatch = useDispatch();

  const [invoicesCurrent, setInvoicesCurrent] = React.useState([]);

  useEffect(() => {
    dispatch(getInvoices());
  }, [dispatch]);

  useEffect(() => {
    setInvoicesCurrent(invoices.filter((invoice) => Number(invoice.invoiceDate.substring(5, 7)) === month));
  }, [invoices, month, dispatch]);
  
  ...

  // Link component used: invoice is the one of invoice in invoices state
    <Link to='/invoice/create'
          state={{ ...invoice }}>
      <Button>Modify</Button>
    </Link>

// Invoice.js

const InvoiceComponent = () => {
  const location = useLocation();
  const invoice = location.state;
  const [company, setCompany] = useState(invoice ? invoice.company : '');
  const [employee, setEmployee] = useState(invoice ? invoice.employee : '');
  const [invoiceDate, setInvoiceDate] = useState(invoice ? invoice.invoiceDate : new Date());
  const [orderId, setOrderId] = useState(invoice ? invoice.orderId : '');
  const [companyTel, setCompanyTel] = useState(invoice ? invoice.companyTel : '');
  const [companyFax, setCompanyFax] = useState(invoice ? invoice.companyFax : '');

  const items = useSelector((state) => state.items);
  const dispatch = useDispatch();

  useEffect(() => {
    const last = document.getElementById(`row-${items.length - 1}-0`);
    if (last != null) last.focus();
  }, [items.length]);

  useEffect(() => {
    if (invoice) {
      dispatch(updateItems(invoice.items));
    }
  }, [dispatch, invoice]);

  ...

我必须分享当前的应用行为。

  1. 单击 'Modify' 按钮后,创建页面会加载发票数据。
  2. 然后使用 'Go back'、'Go forward' 导航或单击 link 到两个页面中的任何一个都会显示上部错误。
  3. 在调用 setInvoicesCurrent 的 Invoices.js 中的 useEffect 挂钩中,
    当我 console.log(invoices) 时,它不是发票数组,而是其他状态(项目)的数组,用于 Invoice.js
  4. 刷新页面会使所有内容重置。

是否有导航时管理 redux 存储的指南?

// console.log(invoices) in useEffect calling setInvoicesCurrent
// Normally opened:
invoices
(6) [{…}, {…}, {…}, {…}, {…}, {…}]
0: {_id: '1', company: 'cmp1', employee: 'e1', invoiceDate: '2022-01-07T05:14:15.482Z', orderId: '', …}
1: {_id: '2', company: 'cmp2', employee: 'e1', invoiceDate: '2022-01-07T05:14:15.482Z', orderId: '', …}
2: {_id: '3', company: 'comp3', employee: 'e1', invoiceDate: '2022-01-07T05:14:15.482Z', orderId: '', …}
3: {_id: '4', company: 'comp4', employee: 'e1', invoiceDate: '2022-01-07T05:14:15.482Z', orderId: '', …}
4: {_id: '5', company: 'comp5', employee: 'e1', invoiceDate: '2022-01-07T05:14:15.482Z', orderId: '', …}
5: {_id: '6', company: 'comp6', employee: 'e1', invoiceDate: '2022-01-07T13:10:56.380Z', orderId: '', …}
length: 6 [[Prototype]]: Array(0)

Each Array has the following data
0:
company: "cmp1"
companyFax: "1222222222"
companyTel: "122331232"
employee: "e1"
invoiceDate: "2022-01-07T05:14:15.482Z"
items: Array(2)
0: {name: 'item1', spec: 'spec1', qty: 1, price: 10000, total: 10000, …}
1: {name: 'item2', spec: 'spec2', qty: 20, price: 1000, total: 20000, …}
length: 2
[[Prototype]]: Array(0)
modifiedOn: "2022-01-07T05:25:14.771Z"
orderId: ""
__v: 0
_id: "1"

// console.log(invoices) when ERROR occurs:
invoices
(6) [Array(2), Array(2), Array(2), Array(2), Array(2), Array(2)]
0: Array(2)
0: {name: 'item1', spec: 'spec1', qty: 1, price: 10000, total: 10000, …}
1: {name: 'item2', spec: 'spec2', qty: 20, price: 1000, total: 20000, …}
length: 2

[[Prototype]]: Array(0)
1: Array(2)
0: {name: 'item1', spec: 'spec1', qty: 1, price: 10000, total: 10000, …}
1: {name: 'item2', spec: 'spec2', qty: 20, price: 1000, total: 20000, …}

length: 2
[[Prototype]]: Array(0)
2: (2) [{…}, {…}]
3: (2) [{…}, {…}]
4: (2) [{…}, {…}]
5: (2) [{…}, {…}]
length: 6
[[Prototype]]: Array(0)

您不应该将数组解构为对象,它会创建一个对象。

像下面这样使用

// Invoices.js
<Link to="/invoice/create" state={{ invoice }}>
  <Button>Modify</Button>
</Link>;

// Invoice.js
const { invoice } = location.state;

注:

const a = [1,2,3];
console.log({...a}); // {0: 1, 1: 2, 2: 3}