#javascript #reactjs
Вопрос:
Если вы посмотрите на мой JSX, я пытаюсь создать размеры из product
объекта, проблема в том, что, когда я зацикливаюсь product.size.map()
, он выдает ошибку, в которой говорится product
, что она не определена.
Как это решить?
обновление Мне удалось выполнить некоторые обходные пути, но я уверен, что это не считается лучшей практикой.
import React , {useState , useEffect} from 'react'
import { Row, Col, Image, ListGroup, Card, Button } from 'react-bootstrap'
import {Link} from 'react-router-dom'
import Rating from '../components/Rating'
import axios from 'axios'
const ProductScreen = ({match}) => {
const [product , setProduct] = useState({})
useEffect(()=>{
let componentMounted = true
const fetchProducts = async ()=>{
const {data} = await axios.get(`http://172.30.246.130:5000/api/products/${match.params.id}`)
if(componentMounted){
setProduct(data)
}
}
fetchProducts()
return () => {
componentMounted = false
}
},[match])
if(Object.keys(product).length===0) return null // this is the workaround I have done what do you think?
else{
return (
<>
<Link className='btn btn-light my-3' to='/'>
Go Back
</Link>
<Row>
<Col md={6}>
<Image src={product.image} alt={product.name} />
</Col>
<Col md={3}>
<ListGroup variant='flush'>
<ListGroup.Item>
<h3>{product.name}</h3>
</ListGroup.Item>
<ListGroup.Item>
<Rating rating={product.rating} reviews={product.numReviews}/>
</ListGroup.Item>
<ListGroup.Item>
<strong> Price: ${product.price}</strong>
</ListGroup.Item>
<ListGroup.Item>
<strong>Description :</strong> {product.description}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={3}>
<Card>
<ListGroup>
<ListGroup.Item>
<Row>
<Col>
Price :
</Col>
<Col>
<strong>${product.price}</strong>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>
Status :
</Col>
<Col>
<strong>{product.countInStock > 0 ? 'In Stock' : "Out Of Stock"}</strong>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>
Sizes :
</Col>
<Col>
{product.size.map(s=><Button key={s} className='p-2 m-1'>{s}</Button>)}
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item className='d-grid gap-2'>
<Button type='button' disabled={product.countInStock === 0}>
Add To Cart
</Button>
</ListGroup.Item>
</ListGroup>
</Card>
</Col>
</Row>
</>
)
}}
export default ProductScreen
import React , {useState , useEffect} from 'react'
import { Row, Col, Image, ListGroup, Card, Button } from 'react-bootstrap'
import {Link} from 'react-router-dom'
import Rating from '../components/Rating'
import axios from 'axios'
const ProductScreen = ({match}) => {
const [product , setProduct] = useState({})
useEffect(()=>{
let componentMounted = true
const fetchProducts = async ()=>{
const {data} = await axios.get(`http://172.30.246.130:5000/api/products/${match.params.id}`)
if(componentMounted){
setProduct(data)
}
}
fetchProducts()
return () => {
componentMounted = false
}
},[match,product ])
return (
<>
<Link className='btn btn-light my-3' to='/'>
Go Back
</Link>
<Row>
<Col md={6}>
<Image src={product.image} alt={product.name} />
</Col>
<Col md={3}>
<ListGroup variant='flush'>
<ListGroup.Item>
<h3>{product.name}</h3>
</ListGroup.Item>
<ListGroup.Item>
<Rating rating={product.rating} reviews={product.numReviews}/>
</ListGroup.Item>
<ListGroup.Item>
<strong> Price: ${product.price}</strong>
</ListGroup.Item>
<ListGroup.Item>
<strong>Description :</strong> {product.description}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={3}>
<Card>
<ListGroup>
<ListGroup.Item>
<Row>
<Col>
Price :
</Col>
<Col>
<strong>${product.price}</strong>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>
Status :
</Col>
<Col>
<strong>{product.countInStock > 0 ? 'In Stock' : "Out Of Stock"}</strong>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>
Sizes :
</Col>
<Col>
{console.log(product)}
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item className='d-grid gap-2'>
<Button type='button' disabled={product.countInStock === 0}>
Add To Cart
</Button>
</ListGroup.Item>
</ListGroup>
</Card>
</Col>
</Row>
</>
)
}
export default ProductScreen
Комментарии:
1.«он выдал ошибку, в которой говорится, что продукт не определен». Держу пари, что он сказал
product.size
undefined
(нетproduct
). «когда я зацикливаюсь наproduct.size.map()
…»product.size.map
нигде не появляется в предоставленном вами коде.
Ответ №1:
Вы не можете предотвратить отображение начального состояния.
(Я добавил обновление внизу, связанное с обновленным вопросом.)
Если этот компонент не может быть с пользой отрисован без product
, то product
он должен быть опорой, которую он получает, а не членом государства, которого он выбирает. Выборка должна быть в родительском компоненте.
Но если вы хотите, чтобы выборка осталась в компоненте, вам нужно установить значение маркера (например null
) и разветвить рендеринг на основе этого значения маркера, например:
if (!product) {
return /* ...render a "loading" message... */;
}
// ..render `product` here...
Повторите свой отредактированный вопрос: Похоже, у вас возникли проблемы product.size.map(/*...*/)
. Если мы посмотрим на ваше начальное состояние, у вас есть:
const [product, setProduct] = useState({});
Так как у него нет size
свойства, product.size
есть undefined
и product.size.map
произойдет сбой с ошибкой о product.size
бытии undefined
.
Вы не показали код , который пытается это сделать product.size.map
, но у вас есть различные варианты.
Тебе бы не помешал охранник:
{product.size amp;amp; product.size.map(/*...*/)}
Вы можете включить пустой массив в исходное состояние:
const [product, setProduct] = useState({size: []});
Комментарии:
1. Спасибо, было бы мило с вашей стороны, если бы вы могли проверить мой отредактированный вопрос, поскольку он кажется реальной проблемой, с которой я сталкиваюсь.
2. Большое вам спасибо за ваше решение, теперь моя проблема решена, и это имеет смысл.
3. Рад, что это помогло! 🙂 Счастливого кодирования!
Ответ №2:
Удалите product
из зависимостей useEffect
as, которые вызовут обратный вызов и вызовут бесконечный цикл.
useEffect(() => {
...
},[match])
Чтобы ничего не отображать до тех пор, пока product
оно не будет извлечено, используйте ложное значение, например undefined/null
, в качестве начального состояния:
const [product , setProduct] = useState();
и проверьте product
, прежде чем повторно использовать JSX:
if(!product) return null;
return (
<>
<Link className='btn btn-light my-3' to='/'>
...
)
Комментарии:
1. Хороший момент в отношении зависимости, я бы даже использовал
match.params.id
, у match могут быть другие параметры, от которых зависят другие компоненты, но у этого нет. Возможно, это сэкономит некоторые рендеры. Короткое замыкание с возвращением нуля-это то, что я тоже делаю, если выборка, скорее всего, будет короткой.2. @Ramesh Reddy спасибо за ваш ответ, если вы посмотрите на мой jsx, я использую
product
объект, и когда я регистрирую его в консоли, кажется, что у него два значения: первое{}
и второе-объект, который я хочу. проблема в том, что когда я визуализирую изображение сperson
объекта, он сначала говорит «неопределенный», что для меня очень странно.3. Я отредактировал свой вопрос в соответствии с проблемой, с которой я в настоящее время сталкиваюсь
4. @TankOne Вы все еще можете следить за моим ответом, чтобы исправить ошибку в обновленном вопросе