Uncaught ReferenceError: Cannot access 'ordersToDisplay' before initialization - trying to update value on re-render React

Viewed 133

I am trying to set the title of my document to "/{orderNumber}orders" and for that orderNumber value to update every time user clicks the button and different number of orders from filtered array are displayed on the screen.

For context, I am importing a json file, filtering it to display the correct elements I want decided by user input, and I am then calculating the length of that array, of which that integer needs to be stored in orderNumber variable to update document title.

I know I am accessing the correct value of the arrays as I have console logged it, my issue is how to update this state change every re render without this error throwing: (Uncaught ReferenceError: Cannot access 'ordersToDisplay' before initialization)

Code:

import { Col, Row } from "antd";
import { useContext, useEffect, useMemo, useState } from "react";
import Order from "../components/Order";
import { AppContext } from "../context/Context";
import AntButton from "../elements/Button";
import ordersToDisplay from "../orders.json";

const OrdersPage = () => {
    const [filteringStatus, setFilteringStatus] = useState("");
    const {orderAmount, setOrderAmount} = useContext(AppContext)
    const [test, setTest] = useState("")

    const setDiplayAcceptedOrders = () => {
        setFilteringStatus("accepted");
        setTest(ordersToDisplay.length)
    };
    
    const setDiplayCompletedOrders = () => {
        setFilteringStatus("complete");
        setTest(ordersToDisplay.length)
    };
    
    const setDiplayInProgressOrders = () => {
        setFilteringStatus("inProgress");
        setTest(ordersToDisplay.length)
    };


    const ordersToDisplay = useMemo(() => {
        if (filteringStatus) {
          return ordersToDisplay.filter((i) => i.orderStatus === filteringStatus);
        }
        return ordersToDisplay;
    }, [filteringStatus]);


    console.log("Orders to display: ", ordersToDisplay);
    console.log("test value: ", test)



    return(
        <div className="container">
            <Row justify="space-between" align="middle">
                <Col span={6}>
                    <h1>Orders</h1>
                </Col>
                <Col span={6}>
                    <AntButton onClick={setDiplayAcceptedOrders} name="Accepted"/>
                </Col>
                <Col span={6}>
                    <AntButton onClick={setDiplayInProgressOrders}  name="In Progress"/>
                </Col>
                <Col span={6}>
                    <AntButton onClick={setDiplayCompletedOrders} name="Complete"/>
                </Col>
            </Row>
            <Row>
                <Col span={12}>
                    <h3>{filteringStatus == "" ? "All Orders" : filteringStatus}</h3>
                    {ordersToDisplay.map((e) => {
                        return(
                            <Order
                            key={e.id}
                            productName={e.productName}
                            dateOrdered={e.dateOrdered}
                            orderStatus={e.orderStatus}
                        />
                        )
                    })}
                </Col>
            </Row>
        </div>
    )
}

export default OrdersPage;

app

const App = () => {
    const [orderAmount, setOrderAmount] = useState("")

    const Routes = useRoutes([
        {path: "/", element: <HomePage/>},
        {path: `/(${orderAmount})orders`, element: <OrdersPage/>}
    ])
    
  return (
        <AppContext.Provider value={{
            orderAmount, setOrderAmount
        }}>
            <div>
                {Routes}
            </div>
        </AppContext.Provider>
  );
};

export default App;
1 Answers

You are masking the imported ordersToDisplay with what you are trying to memoize. Rename the memoized version/variable. You need only store in state the current filteringStatus state, the test state seems unnecessary and isn't used from what I see.

To update the orderAmount state in the context, use a useEffect hook with a dependency on the computed/memoized orders value to issue a side-effect to update the orderAmount value.

Example:

import { Col, Row } from "antd";
import { useContext, useEffect, useMemo, useState } from "react";
import Order from "../components/Order";
import { AppContext } from "../context/Context";
import AntButton from "../elements/Button";
import ordersToDisplay from "../orders.json";

const OrdersPage = () => {
  const [filteringStatus, setFilteringStatus] = useState("");
  const { orderAmount, setOrderAmount } = useContext(AppContext);

  const setDiplayAcceptedOrders = () => {
    setFilteringStatus("accepted");
  };
    
  const setDiplayCompletedOrders = () => {
    setFilteringStatus("complete");
  };
    
  const setDiplayInProgressOrders = () => {
    setFilteringStatus("inProgress");
  };

  // rename to something else, anything but ordersToDisplay
  const orders = useMemo(() => {
    if (filteringStatus) {
      return ordersToDisplay.filter((i) => i.orderStatus === filteringStatus);
    }
    return ordersToDisplay;
  }, [filteringStatus]);

  useEffect(() => {
    console.log("Orders to display: ", orders); // <-- output derived value

    // update amount when orders array updates
    setOrderAmount(orders.length);
  }, [orders, setOrderAmount]);

  return (
    <div className="container">
      <Row justify="space-between" align="middle">
        <Col span={6}>
          <h1>Orders</h1>
        </Col>
        <Col span={6}>
          <AntButton onClick={setDiplayAcceptedOrders} name="Accepted"/>
        </Col>
        <Col span={6}>
          <AntButton onClick={setDiplayInProgressOrders}  name="In Progress"/>
        </Col>
        <Col span={6}>
          <AntButton onClick={setDiplayCompletedOrders} name="Complete"/>
        </Col>
      </Row>
      <Row>
        <Col span={12}>
          <h3>{filteringStatus == "" ? "All Orders" : filteringStatus}</h3>
          {orders.map((e) => { // <-- use here
            return (
              <Order
                key={e.id}
                productName={e.productName}
                dateOrdered={e.dateOrdered}
                orderStatus={e.orderStatus}
              />
            )
          })}
        </Col>
      </Row>
    </div>
  );
};

export default OrdersPage;
Related