英文:
getting id from url in reactRouter v6
问题
I am following an ecommerce tutorial, which was done with react V5 and I'm trying to remake it in react V6. Problem I faced includes url. I am building Order details page, which should contain details about the placed order. After clicking "Place Order" button I am getting an error, saying: "Matched leaf route at location "/order/34" does not have an element. This means it will render an
OrderScreen.js:
import React, { useState, useEffect } from 'react';
import { Form, Button, Row, Col, ListGroup, Image, Card, ListGroupItem } from 'react-bootstrap';
import { useDispatch, useSelector } from 'react-redux';
import Message from '../components/Message';
import Loader from '../components/Loader';
import { Redirect, Link, useNavigate, useParams, useLocation, useMatch } from 'react-router-dom';
import { getOrderDetails } from '../actions/orderActions';
import { ORDER_CREATE_RESET } from '../constants/orderConstants';
function OrderScreen({ match }) {
const orderId = match.params.id;
const orderDetails = useSelector(state => state.orderDetails);
const { order, error, loading } = orderDetails;
const navigate = useNavigate();
const dispatch = useDispatch();
if (!loading && !error) {
order.itemsPrice = order.orderItems.reduce((acc, item) => acc + item.price * item.qty, 0).toFixed(2);
}
useEffect(() => {
if (!order || order._id !== Number(orderId)) {
dispatch(getOrderDetails(orderId));
console.log("yes");
}
}, [dispatch, navigate, order, orderId]);
return loading ? (
<Loader />
) : error ? (
<Message variant='danger'>{error}</Message>
) : (
<div>
<Row>
<Col md={8}>
<ListGroup variant='flush'>
<ListGroup.Item>
<h2>Shipping</h2>
<p>
<strong>Shipping: </strong>
{order.shippingAddress.address}, {order.shippingAddress.city},
{', '}
{order.shippingAddress.postalCode},
{', '}
{order.shippingAddress.country}.
</p>
</ListGroup.Item>
<ListGroup.Item>
<h2>Payment Method</h2>
<p>
<strong>Method: </strong>
{order.paymentMethod}
</p>
</ListGroup.Item>
<ListGroup.Item>
<h2>Order Items</h2>
{order.orderItems.length === 0 ? (
<Message variant='info'>
Your order is empty
</Message>
) : (
<ListGroup variant='flush'>
{order.orderItems.map((item, index) => (
<ListGroup.Item key={index}>
<Row>
<Col md={1}>
<Image src={item.image} alt={item.name} fluid rounded></Image>
</Col>
<Col>
<Link to={'/product/' + item.product}>{item.name}</Link>
</Col>
<Col md={4}>
{item.qty} X ${item.price} = ${(item.qty * item.price).toFixed(2)}
</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>
)}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={4}>
<Card>
<ListGroup variant='flush'>
<ListGroup.Item>
<h2>Order Summary</h2>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Item:</Col>
<Col>${order.itemsPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Shipping:</Col>
<Col>${order.shippingPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Tax:</Col>
<Col>${order.taxPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Total:</Col>
<Col>${order.totalPrice}</Col>
</Row>
</ListGroup.Item>
</ListGroup>
</Card>
</Col>
</Row>
</div>
);
}
export default OrderScreen;
orderActions.js:
export const getOrderDetails = (id) => async (dispatch, getState) => {
try {
dispatch({
type: ORDER_DETAILS_REQUEST,
});
const {
userLogin: { userInfo },
} = getState();
const config = {
headers: {
'Content-type': 'application/json',
Authorization: 'Bearer ' + userInfo.token,
},
};
const { data } = await axios.get(
'/api/orders/' + id,
config
);
dispatch({
type: ORDER_DETAILS_SUCCESS,
payload: data
});
} catch (error) {
dispatch({
type: ORDER_DETAILS_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message,
});
}
}
In App.js: I have imported OrderScreen and inserted:
<Route path='/order/:id' component={<OrderScreen />} />
in Routes container.
英文:
I am following an ecommerce tutorial, which was done with react V5 and I'm trying to remake it in react V6. Problem I faced includes url. I am building Order details page, which should contain details about the placed order. After clicking "Place Order" button I am getting an error, saying: tched leaf route at location "/order/34" does not have an element. This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.
OrderScreen.js:
import React, { useState, useEffect } from 'react'
import { Form, Button, Row, Col, ListGroup, Image, Card, ListGroupItem } from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import Message from '../components/Message'
import Loader from '../components/Loader'
import { Redirect, Link, useNavigate, useParams, useLocation, useMatch } from 'react-router-dom'
import { getOrderDetails } from '../actions/orderActions'
import { ORDER_CREATE_RESET } from '../constants/orderConstants'
function OrderScreen({match}) {
const orderId = match.params.id
const orderDetails = useSelector(state => state.orderDetails)
const { order, error, loading } = orderDetails
const navigate = useNavigate()
const dispatch = useDispatch()
if(!loading && !error){
order.itemsPrice = order.orderItems.reduce((acc, item) => acc + item.price * item.qty, 0).toFixed(2)
}
useEffect(() => {
if(!order || order._id !== Number(orderId)){
dispatch(getOrderDetails(orderId))
console.log("yes")
}
}, [dispatch,navigate,order,orderId])
return loading ? (
<Loader/>
) : error ? (
<Message variant='danger'>{error}</Message>
) : (
<div>
<Row>
<Col md={8}>
<ListGroup variant='flush'>
<ListGroup.Item>
<h2>Shipping</h2>
<p>
<strong>Shipping: </strong>
{order.shippingAddress.address}, {order.shippingAddress.city},
{' '}
{order.shippingAddress.postalCode},
{' '}
{order.shippingAddress.country}.
</p>
</ListGroup.Item>
<ListGroup.Item>
<h2>Payment Method</h2>
<p>
<strong>Method: </strong>
{order.paymentMethod}
</p>
</ListGroup.Item>
<ListGroup.Item>
<h2>Order Items</h2>
{order.orderItems.length===0 ? <Message variant='info'>
Your order is empty
</Message> : (
<ListGroup variant='flush'>
{order.orderItems.map((item, index) => (
<ListGroup.Item key={index}>
<Row>
<Col md={1}>
<Image src={item.image} alt={item.name} fluid rounded></Image>
</Col>
<Col>
<Link to={'/product/'+item.product}>{item.name}</Link>
</Col>
<Col md={4}>
{item.qty} X ${item.price} = ${(item.qty * item.price).toFixed(2)}
</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>
)}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={4}>
<Card>
<ListGroup varaint='flush'>
<ListGroup.Item>
<h2>Order Summary</h2>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Item:</Col>
<Col>${order.itemsPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Shipping:</Col>
<Col>${order.shippingPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Tax:</Col>
<Col>${order.taxPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Total:</Col>
<Col>${order.totalPrice}</Col>
</Row>
</ListGroup.Item>
{/* <ListGroup.Item>
<Button
type='button'
className='btn-block'
disabled={order.orderItems === 0}
onClick={placeOrder}
>
Place Order
</Button>
</ListGroup.Item> */}
</ListGroup>
</Card>
</Col>
</Row>
</div>
)
}
export default OrderScreen
orderActions.js:
export const getOrderDetails = (id) => async (dispatch, getState) => {
try{
dispatch({
type: ORDER_DETAILS_REQUEST,
})
const {
userLogin: { userInfo },
} = getState()
const config = {
headers:{
'Content-type': 'application/json',
Authorization: 'Bearer '+userInfo.token,
}
}
const { data } = await axios.get(
'/api/orders/'+id,
config
)
dispatch({
type: ORDER_DETAILS_SUCCESS,
payload: data
})
}catch(error){
dispatch({
type:ORDER_DETAILS_FAIL,
payload:error.response && error.response.data.detail
? error.response.data.detail
: error.message,
})
}
}
In App.js: I have imported OrderScreen and inserted
<Route path='/order/:id' component={<OrderScreen/>} />
in Routes container.
答案1
得分: 2
以下是翻译好的部分:
Matched leaf route at location "/order/34" does not have an element.
This means it will render an with a null value by default resulting in
an "empty" page.
匹配到的叶子路由位于位置"/order/34",但没有指定元素。
这意味着默认情况下会渲染一个具有空值的元素,导致页面为空。
The react-router-dom@6
Route
component doesn't have any component
prop. The Route
renders all content on a single element
prop. The error is saying you have a Route
with no element to render.
react-router-dom@6
中的 Route
组件没有 component
属性。Route
在单个 element
属性上渲染所有内容。错误提示表示您有一个没有要渲染的元素的 Route
。
<Route path='/order/:id' element={<OrderScreen />} />
在这之后,OrderScreen
组件将无法访问 id
路由参数,因为现在也没有任何路由属性。上面的 JSX 应该明确表明没有传递给 OrderScreen
任何属性。使用 useParams
钩子来访问路由路径参数。
...
import { ... useParams, ... } from 'react-router-dom';
...
function OrderScreen() {
const dispatch = useDispatch();
const navigate = useNavigate();
const { id } = useParams();
const { order, error, loading } = useSelector(state => state.orderDetails);
useEffect(() => {
if (!order || String(order._id) !== id){
dispatch(getOrderDetails(id))
console.log("yes")
}
}, [dispatch, order, id]);
if (loading) {
return <Loader />;
}
if (error) {
return <Message variant='danger'>{error}</Message>;
}
// 不要改变状态!!在渲染时计算派生的总价格。
const orderItemsPrice = order.orderItems.reduce(
(acc, item) => acc + item.price * item.qty,
0
).toFixed(2);
return (
<div>
...
</div>
);
}
export default OrderScreen;
英文:
> Matched leaf route at location "/order/34" does not have an element.
> This means it will render an with a null value by default resulting in
> an "empty" page.
The react-router-dom@6
Route
component doesn't have any component
prop. The Route
renders all content on a single element
prop. The error is saying you have a Route
with no element to render.
<Route path='/order/:id' element={<OrderScreen />} />
After this, the OrderScreen
component will have an issue accessing the id
route path param as there are now also not any route props. The above JSX should make it overtly clear that no props are passed to OrderScreen
. Use the useParams
hook to access the route path params
...
import { ... useParams, ... } from 'react-router-dom';
...
function OrderScreen() {
const dispatch = useDispatch();
const navigate = useNavigate();
const { id } = useParams();
const { order, error, loading } = useSelector(state => state.orderDetails);
useEffect(() => {
if (!order || String(order._id) !== id){
dispatch(getOrderDetails(id))
console.log("yes")
}
}, [dispatch, order, id]);
if (loading) {
return <Loader />;
}
if (error) {
return <Message variant='danger'>{error}</Message>;
}
// Don't mutate state!! Compute derived total price when rendering.
const orderItemsPrice = order.orderItems.reduce(
(acc, item) => acc + item.price * item.qty,
0
).toFixed(2);
return (
<div>
...
</div>
);
}
export default OrderScreen;
答案2
得分: 1
exsample:
<Route path='userPage/:userId' element={ <UserPage /> } />
// 在其他页面中,您可以重定向到用户页面:
<Link to={`userPage/${userId}`} > 前往用户页面 </Link>
// 在UserPage组件中,您可以使用useParams钩取到UserId:
const {userId} = useparams( )
英文:
exsample :
<Route path='userPage/:userId' element={ <UserPage /> } />
// in other page that you want redirect to userPage :
<Link to={`userPage/${userId}`} > go to user page </Link>
// in userPage component you can take UserId using useParams hook :
const {userId} = useparams( )
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论