在将状态传递给 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]);
...
我必须分享当前的应用行为。
- 单击 'Modify' 按钮后,创建页面会加载发票数据。
- 然后使用 'Go back'、'Go forward' 导航或单击 link 到两个页面中的任何一个都会显示上部错误。
- 在调用 setInvoicesCurrent 的 Invoices.js 中的 useEffect 挂钩中,
当我 console.log(invoices) 时,它不是发票数组,而是其他状态(项目)的数组,用于 Invoice.js
- 刷新页面会使所有内容重置。
是否有导航时管理 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}
我正在用 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]);
...
我必须分享当前的应用行为。
- 单击 'Modify' 按钮后,创建页面会加载发票数据。
- 然后使用 'Go back'、'Go forward' 导航或单击 link 到两个页面中的任何一个都会显示上部错误。
- 在调用 setInvoicesCurrent 的 Invoices.js 中的 useEffect 挂钩中,
当我 console.log(invoices) 时,它不是发票数组,而是其他状态(项目)的数组,用于 Invoice.js - 刷新页面会使所有内容重置。
是否有导航时管理 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}