Node.js 产品未显示在前端

Node.js 产品未显示在前端,node.js,reactjs,Node.js,Reactjs,嗨,伙计们,我在用我的产品的不同方式显示数据时遇到了一个问题。如果你知道bradtraversy关于电子商务的新课程,我试着在完成课程后修改我的代码 首先获取api/products/:id 此api从课程中获取mongoDb上的产品id及其默认值 第二,我将用不同的方式使用slug调用它,我已经在mongoDb创建了slug,但问题是消息说 TypeError: Cannot read property 'length' of undefined 所以我自己检查我的产品,不在前端显示数据,而

嗨,伙计们,我在用我的产品的不同方式显示数据时遇到了一个问题。如果你知道bradtraversy关于电子商务的新课程,我试着在完成课程后修改我的代码

首先获取api/products/:id

此api从课程中获取mongoDb上的产品id及其默认值

第二,我将用不同的方式使用slug调用它,我已经在mongoDb创建了slug,但问题是消息说

TypeError: Cannot read property 'length' of undefined
所以我自己检查我的产品,不在前端显示数据,而是在后端显示数据

所以我会把代码带到这里:

后端产品控制器

    const getProductBySlug = asyncHandler(async (req, res) => {
      const product = await Product.find({ slug: req.params.slug })
      console.log(product)
      if (product) {
        res.json(product)
      } else {
        res.status(404)
        throw new Error('Product not found')
      }
    })
this is my product reducer
export const productDetailsReducer = (
  state = { product: { reviews: [] } },
  action
) => {
  switch (action.type) {
    case PRODUCT_DETAILS_REQUEST:
      return { loading: true, ...state }
    case PRODUCT_DETAILS_SUCCESS:
      return { loading: false, product: action.payload }
    case PRODUCT_DETAILS_FAIL:
      return { loading: false, error: action.payload }
    default:
      return state
  }
}
生产活动

export const listProductDetails = (slug) => async (dispatch) => {
  try {
    dispatch({ type: PRODUCT_DETAILS_REQUEST })

    const { data } = await axios.get(`/api/products/slug/${slug}`)

    dispatch({
      type: PRODUCT_DETAILS_SUCCESS,
      payload: data,
    })
  } catch (error) {
    const message =
      error.response && error.response.data.message
        ? error.response.data.message
        : error.message
    if (message === 'Not authorized, token failed') {
      dispatch(logout())
    }
    dispatch({
      type: PRODUCT_DETAILS_FAIL,
      payload: message,
    })
  }
}
在redux扩展中,它的成功调用了chrome,但成功后显示错误

有什么线索吗?这是在控制台中使用morgan的结果

编辑:

我决定加入我的产品屏幕

import {
  listProductDetails,
  createProductReview,
} from '../actions/productActions'
import { PRODUCT_CREATE_REVIEW_RESET } from '../constants/productsConstants'

const ProductScreen = ({ history, match }) => {
  const [qty, setQty] = useState(1)
  const [rating, setRating] = useState(0)
  const [comment, setComment] = useState('')

  const dispatch = useDispatch()

  const userLogin = useSelector((state) => state.userLogin)
  const { userInfo } = userLogin

  const productDetails = useSelector((state) => state.productDetails)
  const { loading, error, product } = productDetails

  const productCreateReview = useSelector((state) => state.productCreateReview)
  const {
    success: successProductReview,
    // loading: loadingProductReview,
    error: errorProductReview,
  } = productCreateReview

  useEffect(() => {
    if (successProductReview) {
      alert('Review Submitted!')
      setRating(0)
      setComment('')
      dispatch({ type: PRODUCT_CREATE_REVIEW_RESET })
    }

    dispatch(listProductDetails(match.params.slug))
  }, [dispatch, match, successProductReview])

  const addToCardHandler = () => {
    history.push(`/cart/${match.params.slug}?qty=${qty}`)
  }

  const submitHandler = (e) => {
    e.preventDefault()
    dispatch(
      createProductReview(match.params.slug, {
        rating,
        comment,
      })
    )
  }
  return (
    <>
      <Link className='btn btn-light my-3' to='/'>
        Go Back
      </Link>
      {loading ? (
        <Loader />
      ) : error ? (
        <Message variant='danger'>{error}</Message>
      ) : (
        <>
          <Meta title={product.name} />
          <Row>
            <Col md={6}>
              <Image src={product.image} alt={product.name} fluid />
            </Col>
            <Col md={3}>
              <ListGroup variant='flush'>
                <ListGroup.Item>
                  <h3>{product.name}</h3>
                </ListGroup.Item>
                <ListGroup.Item>
                  <Rating
                    value={product.rating}
                    text={`${product.numReviews} Reviews`}
                  />
                </ListGroup.Item>
                <ListGroup.Item>Price : ${product.price}</ListGroup.Item>
                <ListGroup.Item>
                  Description : ${product.description}
                </ListGroup.Item>
              </ListGroup>
            </Col>
            <Col md={3}>
              <Card>
                <ListGroup variant='flush'>
                  <ListGroup.Item>
                    <Row>
                      <Col> Price : </Col>
                      <Col>
                        <strong>${product.price}</strong>
                      </Col>
                    </Row>
                  </ListGroup.Item>

                  <ListGroup.Item>
                    <Row>
                      <Col> Status : </Col>
                      <Col>
                        {product.countInStock > 0 ? 'In Stock' : 'Out Of Stock'}
                      </Col>
                    </Row>
                  </ListGroup.Item>

                  {product.countInStock > 0 && (
                    <ListGroup.Item>
                      <Row>
                        <Col>Qty</Col>
                        <Col>
                          <Form.Control
                            as='select'
                            value={qty}
                            onChange={(e) => setQty(e.target.value)}
                          >
                            {[...Array(product.countInStock).keys()].map(
                              (x) => (
                                <option key={x + 1} value={x + 1}>
                                  {x + 1}
                                </option>
                              )
                            )}
                          </Form.Control>
                        </Col>
                      </Row>
                    </ListGroup.Item>
                  )}
                  <ListGroup.Item>
                    <Button
                      onClick={addToCardHandler}
                      className='btn-block'
                      type='button'
                      disabled={product.countInStock === 0}
                    >
                      Add To Card
                    </Button>
                  </ListGroup.Item>
                </ListGroup>
              </Card>
            </Col>
          </Row>
          <Row>
            <Col md={6}>
              <h2>Reviews</h2>
              {product.reviews.length === 0 ? (
                <Message>No Reviews</Message>
              ) : (
                <ListGroup variant='flush'>
                  {product.reviews.map((review) => (
                    <ListGroup.Item key={review._id}>
                      <strong>{review.name}</strong>
                      <Rating value={review.rating} />
                      <p>{review.createdAt.substring(0, 10)}</p>
                      <p>{review.comment}</p>
                    </ListGroup.Item>
                  ))}
                  <ListGroup.Item>
                    <h4>Write a Customer Review</h4>
                    {errorProductReview && (
                      <Message variant='danger'>{errorProductReview}</Message>
                    )}
                    {userInfo ? (
                      <Form onSubmit={submitHandler}>
                        <Form.Group controlId='rating'>
                          <Form.Label>Rating</Form.Label>
                          <Form.Control
                            as='select'
                            value={rating}
                            onChange={(e) => setRating(e.target.value)}
                          >
                            <option value=''>Select...</option>
                            <option value='1'>1 - Poor</option>
                            <option value='2'>2 - Fair</option>
                            <option value='3'>3 - Good</option>
                            <option value='4'>4 - Very Good</option>
                            <option value='5'>5 - Excellent</option>
                          </Form.Control>
                        </Form.Group>
                        <Form.Group controlId='comment'>
                          <Form.Label>Comment</Form.Label>
                          <Form.Control
                            as='textarea'
                            row='3'
                            value={comment}
                            onChange={(e) => setComment(e.target.value)}
                          ></Form.Control>
                        </Form.Group>
                        <Button type='submit' variant='primary'>
                          Submit
                        </Button>
                      </Form>
                    ) : (
                      <Message>
                        Please <Link to='/login'>Sign in</Link> to write a
                        review
                      </Message>
                    )}
                  </ListGroup.Item>
                </ListGroup>
              )}
            </Col>
          </Row>
        </>
      )}
    </>
  )
}

export default ProductScreen
导入{
列表产品详细信息,
createProductReview,
}来自“../actions/productActions”
从“../constants/productsConstants”导入{PRODUCT_CREATE_REVIEW_RESET}
const ProductScreen=({history,match})=>{
常量[数量,设置数量]=使用状态(1)
常数[rating,setRating]=useState(0)
const[comment,setComment]=useState(“”)
const dispatch=usedpatch()
const userLogin=useSelector((state)=>state.userLogin)
const{userInfo}=userLogin
const productDetails=useSelector((state)=>state.productDetails)
const{loading,error,product}=productDetails
const productCreateReview=useSelector((状态)=>state.productCreateReview)
常数{
成功:successProductReview,
//加载:加载ProductReview,
错误:errorProductReview,
}=productCreateReview
useffect(()=>{
if(成功产品审查){
警报('已提交审阅!')
设定值(0)
setComment(“”)
分派({type:PRODUCT\u CREATE\u REVIEW\u RESET})
}
分派(listProductDetails(match.params.slug))
},[dispatch,match,successProductReview])
常量addToCardHandler=()=>{
history.push(`/cart/${match.params.slug}?qty=${qty}`)
}
常量submitHandler=(e)=>{
e、 预防默认值()
派遣(
createProductReview(match.params.slug{
评级
评论,,
})
)
}
返回(
回去
{加载(
):错误(
{错误}
) : (
{product.name}
价格:${product.Price}
描述:${product.Description}
价格:
${product.price}
地位:
{product.countInStock>0?'In Stock':'Out Stock'}
{product.countInStock>0&&(
数量
设置数量(即目标值)}
>
{[…数组(product.countInStock.keys()).map(
(x) =>(
{x+1}
)
)}
)}
添加到卡
评论
{product.reviews.length==0(
没有评论
) : (
{product.reviews.map((review)=>(
{review.name}
{review.createdAt.substring(0,10)}

{review.comment}

))} 写一篇客户评论 {errorProductReview&&( {errorProductReview} )} {userInfo( 评级 设置等级(如目标值)} > 选择。。。 1-差 2-公平 3-好 4-非常好 5-非常好 评论 setComment(e.target.value)} > 提交 ) : ( 请登录以写一封电子邮件 回顾 )} )} )} ) } 导出默认产品屏幕
您确定action.payload是产品对象或数组(1)[0=>productObject]

您确定action.payload是产品对象或数组(1)[0=>productObject]

是的,这是数据