Home > other >  useEffect not running in React component
useEffect not running in React component

Time:09-01

I can't get this React component to work. The useEffect is not running so I could the fill the redux state, read the necessary information from that state and display it in the component. I get a lot of errors in the console about a lot of variables being undefined. I need somehow to fill the state with the dispatch and render the component after that. How can I solve this problem?

Console error Console error

import { useEffect } from 'react'
import { Link, useParams } from 'react-router-dom'
import {
  Row,
  Col,
  Image,
  ListGroup,
  Card,
  ListGroupItem,
} from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import Message from '../components/Message'
import Loader from '../components/Loader'
import { getOrderDetails } from '../features/orders/orderDetailsSlice'

const OrderScreen = () => {
  const dispatch = useDispatch()

  const params = useParams()

  const orderId = params.id

  const orderDetails = useSelector((state) => state.orderDetails)

  const { order, isLoading, isError, message } = orderDetails

  if (!isLoading) {
    // Calculate items price
    const addDecimals = (num) => {
      return (Math.round(num * 100) / 100).toFixed(2)
    }

    var itemsPrice = addDecimals(
      order.orderItems.reduce((acc, item) => acc   item.price * item.qty, 0)
    )
  }

  useEffect(() => {
    dispatch(getOrderDetails(orderId))
  }, [dispatch, orderId])

  return isLoading ? (
    <Loader />
  ) : isError ? (
    <Message variant='danger'>{message}</Message>
  ) : (
    <>
      <h1>Order {order._id}</h1>
      <Row>
        <Col md={8}>
          <ListGroup variant='flush'>
            <ListGroup.Item>
              <h2>Shipping</h2>
              <p>
                <strong>Name: </strong> {order.user.name}
              </p>
              <p>
                <strong>Email: </strong>{' '}
                <a href={`mailto:${order.user.email}`}>{order.user.email}</a>
              </p>

              <p>
                <strong>Address: </strong>
                {order.shippingAddress.address}, {order.shippingAddress.city}{' '}
                {order.shippingAddress.postalCode},{' '}
                {order.shippingAddress.country}
              </p>
              {order.isDelivered ? (
                <Message variant='success'>
                  Delivered on {order.deliveredAt}
                </Message>
              ) : (
                <Message variant='danger'>Not Delivered</Message>
              )}
            </ListGroup.Item>

            <ListGroup.Item>
              <h2>Payment Method</h2>
              <p>
                <strong>Method: </strong>
                {order.paymentMethod}
              </p>
              {order.isPaid ? (
                <Message variant='success'>Paid on {order.paidAt}</Message>
              ) : (
                <Message variant='danger'>Not paid</Message>
              )}
            </ListGroup.Item>

            <ListGroup.Item>
              <h2>Order Items</h2>
              {order.orderItems.length === 0 ? (
                <Message>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
                          />
                        </Col>
                        <Col>
                          <Link to={`/product/${item.product}`}>
                            {item.name}
                          </Link>
                        </Col>
                        <Col md={4}>
                          {item.qty} x ${item.price} = $
                          {Number(item.qty * item.price).toFixed(2)}
                        </Col>
                      </Row>
                    </ListGroup.Item>
                  ))}
                </ListGroup>
              )}
            </ListGroup.Item>
          </ListGroup>
        </Col>

        <Col md={4}>
          <Card>
            <ListGroup variant='flush'>
              <ListGroupItem>
                <h2>Order Summary</h2>
              </ListGroupItem>
              <ListGroup.Item>
                <Row>
                  <Col>Items</Col>
                  <Col>${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>
    </>
  )
}  
export default OrderScreen

I removed the calculations from the code and I get a different error in the console.

import { useEffect } from 'react'
import { Link, useParams } from 'react-router-dom'
import {
  Row,
  Col,
  Image,
  ListGroup,
  Card,
  ListGroupItem,
} from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import Message from '../components/Message'
import Loader from '../components/Loader'
import { getOrderDetails } from '../features/orders/orderDetailsSlice'

const OrderScreen = () => {
  const dispatch = useDispatch()

  const params = useParams()

  const orderId = params.id

  const orderDetails = useSelector((state) => state.orderDetails)

  const { order, isLoading, isError, message } = orderDetails


  useEffect(() => {
    dispatch(getOrderDetails(orderId))
  }, [dispatch, orderId])

  return isLoading ? (
    <Loader />
  ) : isError ? (
    <Message variant='danger'>{message}</Message>
  ) : (
    <>
      <h1>Order {order._id}</h1>
      <Row>
        <Col md={8}>
          <ListGroup variant='flush'>
            <ListGroup.Item>
              <h2>Shipping</h2>
              <p>
                <strong>Name: </strong> {order.user.name}
              </p>
              <p>
                <strong>Email: </strong>{' '}
                <a href={`mailto:${order.user.email}`}>{order.user.email}</a>
              </p>

              <p>
                <strong>Address: </strong>
                {order.shippingAddress.address}, {order.shippingAddress.city}{' '}
                {order.shippingAddress.postalCode},{' '}
                {order.shippingAddress.country}
              </p>
              {order.isDelivered ? (
                <Message variant='success'>
                  Delivered on {order.deliveredAt}
                </Message>
              ) : (
                <Message variant='danger'>Not Delivered</Message>
              )}
            </ListGroup.Item>

            <ListGroup.Item>
              <h2>Payment Method</h2>
              <p>
                <strong>Method: </strong>
                {order.paymentMethod}
              </p>
              {order.isPaid ? (
                <Message variant='success'>Paid on {order.paidAt}</Message>
              ) : (
                <Message variant='danger'>Not paid</Message>
              )}
            </ListGroup.Item>

            <ListGroup.Item>
              <h2>Order Items</h2>
              {order.orderItems.length === 0 ? (
                <Message>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
                          />
                        </Col>
                        <Col>
                          <Link to={`/product/${item.product}`}>
                            {item.name}
                          </Link>
                        </Col>
                        <Col md={4}>
                          {item.qty} x ${item.price} = $
                          {Number(item.qty * item.price).toFixed(2)}
                        </Col>
                      </Row>
                    </ListGroup.Item>
                  ))}
                </ListGroup>
              )}
            </ListGroup.Item>
          </ListGroup>
        </Col>

        <Col md={4}>
          <Card>
            <ListGroup variant='flush'>
              <ListGroupItem>
                <h2>Order Summary</h2>
              </ListGroupItem>
              <ListGroup.Item>
                <Row>
                  <Col>Items</Col>
                  {/* <Col>${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>
    </>
  )
}



export default OrderScreen

Error with calculations removed

If I return a simple div, everything works fine and the state is filled. Div return

It seems to have a problem with these 3 paragraphs and I don't know why, because I have those variables in the state. If I comment them out, everything works fine.

  <p>
                <strong>Name: </strong> {order.user.name}
              </p>
              <p>
                <strong>Email: </strong>{' '}
                <a href={`mailto:${order.user.email}`}>{order.user.email}</a>
              </p>

               <p>
                <strong>Address: </strong>
                {order.shippingAddress.address}, {order.shippingAddress.city}{' '}
                {order.shippingAddress.postalCode},{' '}
                {order.shippingAddress.country}
              </p> 

I found the solution. I just needed to specify the objects and arrays within the order object in my initial state.

const initialState = {
  order: {
    orderItems: [],
    user: {},
    shippingAddress: {}
  },
  isError: false,
  isSuccess: false,
  isLoading: false,
  message: '',
}

CodePudding user response:

I think the issue comes from isLoading that is undefined before dispatch your action getOrderDetails. So you enter in your loop.. Try by adding an initialState to orderItems as an empty array or by default turn isLoading as true.

CodePudding user response:

Try replacing this:

  if (!isLoading) {
    // Calculate items price
    const addDecimals = (num) => {
      return (Math.round(num * 100) / 100).toFixed(2)
    }

    var itemsPrice = addDecimals(
      order.orderItems.reduce((acc, item) => acc   item.price * item.qty, 0)
    )
  }

With this:

var itemsPrice = useMemo(() => {
  if (orderDetails?.order) {
    // Calculate items price
    const addDecimals = (num) => {
      return (Math.round(num * 100) / 100).toFixed(2)
    }

    return addDecimals(
      orderDetails.order.orderItems.reduce((acc, item) => acc   item.price * item.qty, 0)
    )
  }
}, [orderDetails])

You are accessing order.orderItems before the data is fetched.

CodePudding user response:

I found the solution. I just needed to specify the objects and arrays within the order object in my initial state.

const initialState = {
  order: {
    orderItems: [],
    user: {},
    shippingAddress: {}
  },
  isError: false,
  isSuccess: false,
  isLoading: false,
  message: '',
}
  • Related