skip to Main Content

Title: Issue with Rendering Components in React StepContent

Description:

I am facing an issue with rendering components in a React Stepper in my application. The Stepper has three steps – "Dispatchs", "Orders", and "Tenders". Each step is supposed to render a specific set of components. But there seems to a problem rendering stepContent 2 and 3

Here’s a full version of my component structure:

import {
  Card,
  Container,
  Stack,
  Step,
  StepContent,
  StepLabel,
  Stepper,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Typography
} from '@mui/material';

import { format, parseISO } from 'date-fns';
import { useEffect, useState } from 'react';

import { useDispatch } from 'react-redux';
import { useParams } from 'react-router-dom';
import NetworkRepository from 'src/app-utils/network_repository';
import Scrollbar from 'src/components/scrollbar';
import OrdersTableRow from '../../orders/order-table-row/order-table-row';
import { useOrderTableFormate } from '../../orders/use-order-table-formate';
import TenderTableRow from '../../tender/tender-table-row/tender-table-row';
import { useTenderTableFormat } from '../../tender/use-tender-table-formate';
import DispatchTableRow from '../dispatches-table-row/dispatch-table-row';
import { useDispatchesTableFormat } from '../use-dispatches-table-formate';

export default function LoadingInstructionDetails() {
  const { id } = useParams();
  const dispatch = useDispatch();
  const [loadingInstructionDetailsData, setLoadingInstructionDetailsData] = useState({});
  const [tenderDetailsData, setTenderDetailsData] = useState([]);
  const [tenderOrderData, setTenderOrderData] = useState();
  const { getStatusText, formatQty, formatQuantity, orderHeaderRow } = useOrderTableFormate();
  const { generateLocation, formatPrice, getPropertyValue, tenderHeaderRow } = useTenderTableFormat();

  const { loadingInstructionHeaderRow } = useDispatchesTableFormat();
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchDetails = async () => {
      try {
        const loadingInstructionDetails = await NetworkRepository.loadingInstructionDetails(id);
        setLoadingInstructionDetailsData(loadingInstructionDetails);

        // Create an array to store promises for fetching tenderDetails and orderDetails
        const detailsPromises = loadingInstructionDetails.loadinginstruction.map(async (loadinginstruction) => {
          const tenderDetails = await NetworkRepository.tenderDetails(loadinginstruction.order_head.tender_head.id);
          const orderDetails = await NetworkRepository.tenderOrder(loadinginstruction.order_head.tender_head.id);
          console.log(' { loadinginstruction, tenderDetails, orderDetails }', { loadinginstruction, tenderDetails, orderDetails })
          return { loadinginstruction, tenderDetails, orderDetails };
        });

        // Wait for all promises to resolve
        const detailsResults = await Promise.all(detailsPromises);

        // Extract the results and update state
        const tenderDetails = detailsResults.map(result => result.tenderDetails);
        const orderDetailsData = detailsResults.map(result => result.orderDetails);

        console.log('tenderDetails dfdsf', tenderDetails)

        setTenderDetailsData(tenderDetails);
        setTenderOrderData(orderDetailsData);

      } catch (error) {
        console.error('Error fetching Dispatch data:', error);
      } finally {
        setLoading(false);
      }
    };
    fetchDetails();
  }, [id]);

  console.log('tenderOrderData', tenderDetailsData)

  return (
    <Container maxWidth="xl">
      <Typography
        sx={{
          paddingTop: '12px',
          paddingBottom: '20px',
          paddingRight: '20px',
        }}
        variant="h4"
      >
        Dispatch Summary
      </Typography>

      {loadingInstructionDetailsData && loadingInstructionDetailsData.loadinginstruction ? (
        <Stack spacing={2} >
          <Stepper orientation="vertical">
            <Step>
              <StepLabel><Typography variant='h6'>Dispatchs</Typography></StepLabel>
              <StepContent>
                <Card sx={{ marginTop: 2 }}>
                  <Scrollbar>
                    <TableContainer sx={{ overflow: 'unset' }}>
                      <Table sx={{ minWidth: 800 }}>
                        <TableHead >
                          <TableRow>
                            {loadingInstructionHeaderRow.map((label, index) => (
                              <TableCell key={index} sx={{ height: '40px' }}>
                                {label.label}
                              </TableCell>
                            ))}
                          </TableRow>
                        </TableHead>
                        <TableBody>
                          {
                            loadingInstructionDetailsData.loadinginstruction.map((loadinginstruction, index) => (
                              <DispatchTableRow
                                orderNo={loadinginstruction.id}
                                invoiceNo={loadinginstruction.lr_number}
                                millName={loadingInstructionDetailsData.mill}
                                name={loadingInstructionDetailsData.trader}
                                date={format(parseISO(loadinginstruction.date), 'MM/dd/yyyy')}
                                vehicleNumber={loadingInstructionDetailsData.vehicle_num}
                                quantity={loadingInstructionDetailsData.total_qty}
                                billedTo={`${loadinginstruction.billing_address.name}n${loadingInstructionDetailsData.billing_gstin}n${loadinginstruction.billing_address.address}`}
                                shipTo={`${loadinginstruction.address.name}n${loadingInstructionDetailsData.address_gstin}n${loadinginstruction.address.address}`}
                                rate={loadinginstruction.product != null ? loadinginstruction.order_head.price : 'Not given'}
                                grade={loadinginstruction.product != null ? loadinginstruction.product.code : 'Not given'}
                              />
                            ))
                          }
                        </TableBody>
                      </Table>
                    </TableContainer>
                  </Scrollbar>
                </Card>
              </StepContent>
            </Step>
            <Step>
              <StepLabel>
                <Typography variant='h6'>Orders</Typography>
              </StepLabel>
              <StepContent>
              {tenderOrderData ? (
                <Card sx={{ marginTop: 2, marginLeft: 4 }}>
                  <Scrollbar>
                    <TableContainer sx={{ overflow: 'unset' }}>
                      <Table sx={{ minWidth: 800 }}>
                        <TableHead>
                          {orderHeaderRow.map((label, index) => (
                            <TableCell key={index} sx={{ height: '40px' }}>
                              {label.label}
                            </TableCell>
                          ))}
                        </TableHead>
                        <TableBody>
                          {tenderOrderData.map((tenderOrder, index) => (
                            tenderOrder.results.map((result) => (
                              <OrdersTableRow
                                key={result.id}
                                ordersId={result.id}
                                traderName={result.trader.name}
                                millName={result.tender_head.mill.name}
                                date={format(parseISO(result.date), 'MM/dd/yyyy')}
                                price={`₹ ${result.price} ${result.tender_head.product.product_type.unit}`}
                                status={getStatusText(result.status)}
                                tenderType={result.tender_head.tender_type}
                                productType={result.tender_head.product.product_type.product_type}
                                grade={
                                  result.tender_head.product.properties.length > 0
                                    ? result.tender_head.product.properties[0].label
                                    : 'Not given'
                                }
                                season={
                                  result.tender_head.product.properties.length > 0
                                    ? result.tender_head.product.properties[0].value
                                    : 'Not given'
                                }
                                sale={formatQty(result.qty)}
                                loading={`${formatQuantity(
                                  result,
                                  'yet_to_load',
                                  result.yet_to_load
                                )} ${result.tender_head.product.product_type.unit}`}
                                dispatched={`${formatQuantity(
                                  result,
                                  'dispatched_qty',
                                  result.yet_to_load
                                )} ${result.tender_head.product.product_type.unit}`}
                                balance={`${formatQuantity(
                                  result,
                                  'available_qty',
                                  result.yet_to_load
                                )} ${result.tender_head.product.product_type.unit}`}
                                order={result.tender_head}
                              />
                            ))))}
                        </TableBody>
                      </Table>
                    </TableContainer>
                  </Scrollbar>
                </Card>
              ) : (<Typography variant="subtitle1" marginLeft={4} paddingTop={4}>This Dispatch has no orders</Typography>)}
            </StepContent>
            </Step>
            <Step>
              <StepLabel><Typography variant='h6'>Tenders</Typography></StepLabel>
              <StepContent>
              <Card sx={{ marginTop: 2, marginLeft: 4 }}>
                <Scrollbar>
                  <TableContainer sx={{ overflow: 'unset' }}>
                    <Table sx={{ minWidth: 800 }}>
                      <TableHead >
                        <TableRow>
                          {tenderHeaderRow.map((label, index) => (
                            <TableCell key={index} sx={{ height: '40px' }}>
                              {label.label}
                            </TableCell>
                          ))}
                        </TableRow>
                      </TableHead>
                      <TableBody>
                        {tenderDetailsData.map((tenderDetails) => (
                          <TenderTableRow
                            key={tenderDetails.id}
                            tenderId={tenderDetails.id}
                            name={tenderDetails.mill.name}
                            location={generateLocation(tenderDetails.mill.location, tenderDetails.mill.state.name)}
                            date={format(parseISO(tenderDetails.date), 'MM/dd/yyyy')}
                            price={formatPrice(tenderDetails.price, tenderDetails.product.product_type.unit)}
                            status={tenderDetails.status}
                            tenderType={tenderDetails.tender_type}
                            productType={tenderDetails.product.product_type.product_type}
                            grade={getPropertyValue(tenderDetails.product.properties, 0, 'label', 'Not given')}
                            season={getPropertyValue(tenderDetails.product.properties, 0, 'value', 'Not given')}
                            total={tenderDetails.qty}
                            sold={tenderDetails.approved_qty}
                            balance={tenderDetails.available_qty}
                          />
                        ))}
                      </TableBody>
                    </Table>
                  </TableContainer>
                </Scrollbar>
              </Card>
              </StepContent>
            </Step>
          </Stepper>
        </Stack>
      ) : (
        <Typography variant="h10">Dispatch details data is null</Typography>
      )}
    </Container>
  );
}

Content of the Stepper is not visible for the "Orders" and “Tenders” steps (Step 2 and 3).

What seems to be the problem? If I remove StepContent in step 2 and 3, I see the components, how do I fix it?

Here some additional info

Minimal reproducible code as requested

import React, { useEffect, useState } from 'react';
import { Card, Container, Stack, Step, StepContent, StepLabel, Stepper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography } from '@mui/material';

export default  MinimalDispatchDetails = () => {
  const [loading, setLoading] = useState(true);
  const [loadingInstructionDetailsData, setLoadingInstructionDetailsData] = useState({ loadinginstruction: [] });

  useEffect(() => {
    const fetchDetails = async () => {
      try {
        // Simulate fetching data
        const loadingInstructionDetails = { loadinginstruction: [...Array(3).keys()].map(index => ({ id: index })) };
        setLoadingInstructionDetailsData(loadingInstructionDetails);
      } catch (error) {
        console.error('Error fetching Dispatch data:', error);
      } finally {
        setLoading(false);
      }
    };
    fetchDetails();
  }, []);

  return (
    <Container maxWidth="xl">
      <Typography variant="h4">Dispatch Summary</Typography>

      {loadingInstructionDetailsData && loadingInstructionDetailsData.loadinginstruction ? (
        <Stack spacing={2}>
          <Stepper orientation="vertical">
            <Step>
              <StepLabel>
                <Typography variant='h6'>Dispatchs</Typography>
              </StepLabel>
              <StepContent>
                <Card sx={{ marginTop: 2 }}>
                  <TableContainer sx={{ overflow: 'unset' }}>
                    <Table sx={{ minWidth: 800 }}>
                      <TableHead>
                        <TableRow>
                          <TableCell>ID</TableCell>
                        </TableRow>
                      </TableHead>
                      <TableBody>
                        {loadingInstructionDetailsData.loadinginstruction.map((loadinginstruction, index) => (
                          <TableRow key={index}>
                            <TableCell>{loadinginstruction.id}</TableCell>
                          </TableRow>
                        ))}
                      </TableBody>
                    </Table>
                  </TableContainer>
                </Card>
              </StepContent>
            </Step>
            <Step>
              <StepLabel>
                <Typography variant='h6'>Order</Typography>
              </StepLabel>
              <StepContent>
                <Card sx={{ marginTop: 2 }}>
                  <TableContainer sx={{ overflow: 'unset' }}>
                    <Table sx={{ minWidth: 800 }}>
                      <TableHead>
                        <TableRow>
                          <TableCell>ID</TableCell>
                        </TableRow>
                      </TableHead>
                      <TableBody>
                        {loadingInstructionDetailsData.loadinginstruction.map((loadinginstruction, index) => (
                          <TableRow key={index}>
                            <TableCell>{loadinginstruction.id}</TableCell>
                          </TableRow>
                        ))}
                      </TableBody>
                    </Table>
                  </TableContainer>
                </Card>
              </StepContent>
            </Step>
            <Step>
              <StepLabel>
                <Typography variant='h6'>Tender</Typography>
              </StepLabel>
              <StepContent>
                <Card sx={{ marginTop: 2 }}>
                  <TableContainer sx={{ overflow: 'unset' }}>
                    <Table sx={{ minWidth: 800 }}>
                      <TableHead>
                        <TableRow>
                          <TableCell>ID</TableCell>
                        </TableRow>
                      </TableHead>
                      <TableBody>
                        {loadingInstructionDetailsData.loadinginstruction.map((loadinginstruction, index) => (
                          <TableRow key={index}>
                            <TableCell>{loadinginstruction.id}</TableCell>
                          </TableRow>
                        ))}
                      </TableBody>
                    </Table>
                  </TableContainer>
                </Card>
              </StepContent>
            </Step>
          </Stepper>
        </Stack>
      ) : (
        <Typography variant="h10">Dispatch details data is null</Typography>
      )}
    </Container>
  );
};





2

Answers


  1. Issue

    You are not passing activeStep prop to Stepper, it doesn’t know which step it needs to highlight.

    By Default, activeStep’s value is 0, that’s why you can see Dispatch only.

    Solution

    Used a activeStep state so that DispatchSummary Component remember which vertical step it is.
    <Stepper orientation="vertical" activeStep={activeStep}>

    DispatchSummary

    import React, { useEffect, useState } from "react";
    import {
      Button,
      Container,
      Paper,
      Stack,
      Step,
      StepContent,
      StepLabel,
      Stepper,
      Typography,
    } from "@mui/material";
    import { LoadingInstructionTable } from "./LoadingInstructionsTable";
    
    export default DispatchSummary = () => {
      const [activeStep, setActiveStep] = useState(0);
      const [loadingInstructionDetailsData, setLoadingInstructionDetailsData] =
        useState({ loadingInstructions: [] });
    
      useEffect(() => {
        const fetchDetails = async () => {
          try {
            const loadingInstructions = [...Array(4).keys()].map((index) => ({
              id: index,
            }));
            setLoadingInstructionDetailsData({ loadingInstructions });
          } catch (error) {
            console.error("Error fetching Dispatch data:", error);
          }
        };
        fetchDetails();
      }, []);
    
      const handleNext = () => {
        setActiveStep((prevActiveStep) => prevActiveStep + 1);
      };
    
      const handleReset = () => {
        setActiveStep(0);
      };
    
      const steps = ["Dispatchs", "Order", "Tender"];
    
      return (
        <Container maxWidth="xl">
          <Typography variant="h4">Dispatch Summary</Typography>
          {loadingInstructionDetailsData?.loadingInstructions && (
            <Stack spacing={2}>
              <Stepper orientation="vertical" activeStep={activeStep}>
                {steps.map((step, index) => (
                  <Step key={index}>
                    <StepLabel>
                      <Typography variant="h6">{step}</Typography>
                    </StepLabel>
                    <StepContent>
                      <LoadingInstructionTable
                        loadingInstructions={
                          loadingInstructionDetailsData.loadingInstructions
                        }
                      />
                      <Stack direction="row" spacing={2}>
                        <Button onClick={handleNext} variant="contained">
                          Next
                        </Button>
                      </Stack>
                    </StepContent>
                  </Step>
                ))}
              </Stepper>
            </Stack>
          )}
          {activeStep === steps.length && (
            <Paper square elevation={0} sx={{ p: 3 }}>
              <Typography>All steps completed - you&apos;re finished</Typography>
              <Button onClick={handleReset} sx={{ mt: 1, mr: 1 }}>
                Reset
              </Button>
            </Paper>
          )}
        </Container>
      );
    };
    

    LoadingInstructionsTable

    import React, { useEffect, useState } from "react";
    import {
      Button,
      Container,
      Paper,
      Stack,
      Step,
      StepContent,
      StepLabel,
      Stepper,
      Typography,
    } from "@mui/material";
    import { LoadingInstructionTable } from "./LoadingInstructionsTable";
    
    export default DispatchSummary = () => {
      const [activeStep, setActiveStep] = useState(0);
      const [loadingInstructionDetailsData, setLoadingInstructionDetailsData] =
        useState({ loadingInstructions: [] });
    
      useEffect(() => {
        const fetchDetails = async () => {
          try {
            const loadingInstructions = [...Array(4).keys()].map((index) => ({
              id: index,
            }));
            setLoadingInstructionDetailsData({ loadingInstructions });
          } catch (error) {
            console.error("Error fetching Dispatch data:", error);
          }
        };
        fetchDetails();
      }, []);
    
      const handleNext = () => {
        setActiveStep((prevActiveStep) => prevActiveStep + 1);
      };
    
      const handleReset = () => {
        setActiveStep(0);
      };
    
      const steps = ["Dispatchs", "Order", "Tender"];
    
      return (
        <Container maxWidth="xl">
          <Typography variant="h4">Dispatch Summary</Typography>
          {loadingInstructionDetailsData?.loadingInstructions && (
            <Stack spacing={2}>
              <Stepper orientation="vertical" activeStep={activeStep}>
                {steps.map((step, index) => (
                  <Step key={index}>
                    <StepLabel>
                      <Typography variant="h6">{step}</Typography>
                    </StepLabel>
                    <StepContent>
                      <LoadingInstructionTable
                        loadingInstructions={
                          loadingInstructionDetailsData.loadingInstructions
                        }
                      />
                      <Stack direction="row" spacing={2}>
                        <Button onClick={handleNext} variant="contained">
                          Next
                        </Button>
                      </Stack>
                    </StepContent>
                  </Step>
                ))}
              </Stepper>
            </Stack>
          )}
          {activeStep === steps.length && (
            <Paper square elevation={0} sx={{ p: 3 }}>
              <Typography>All steps completed - you&apos;re finished</Typography>
              <Button onClick={handleReset} sx={{ mt: 1, mr: 1 }}>
                Reset
              </Button>
            </Paper>
          )}
        </Container>
      );
    };
    

    If you wanna play around with the code.

    Login or Signup to reply.
  2. Stepper component shows only 1 step at a time. You will have to toggle between the steps. This can be achieved by indicating which step is currently active.

    The Stepper component takes activeStep as prop in which you can mention which step is currently active. NOTE: The steps start with index 0.

    I declared the following states:

    const [activeStep, setActiveStep] = useState(0);
    const lastStepIndex = 2;
    

    I added a Button component to toggle between steps.

    Also is there any reason why you wan to show all the steps at the same time?

    Your reproducible code with updated logic:

    import React, { useEffect, useState } from "react";
    import {
      Card,
      Container,
      Stack,
      Step,
      StepContent,
      StepLabel,
      Stepper,
      Table,
      TableBody,
      TableCell,
      TableContainer,
      TableHead,
      TableRow,
      Typography,
      Button,
    } from "@mui/material";
    
    export default App = () => {
      const [loading, setLoading] = useState(true);
      const [loadingInstructionDetailsData, setLoadingInstructionDetailsData] =
        useState({ loadinginstruction: [] });
      const [activeStep, setActiveStep] = useState(0);
      const lastStepIndex = 2;
    
      useEffect(() => {
        const fetchDetails = async () => {
          try {
            // Simulate fetching data
            const loadingInstructionDetails = {
              loadinginstruction: [...Array(3).keys()].map((index) => ({
                id: index,
              })),
            };
            setLoadingInstructionDetailsData(loadingInstructionDetails);
          } catch (error) {
            console.error("Error fetching Dispatch data:", error);
          } finally {
            setLoading(false);
          }
        };
        fetchDetails();
      }, []);
    
      const handleStepChange = () => {
        setActiveStep((prev) => prev + 1);
      };
    
      return (
        <Container maxWidth="xl">
          <Typography variant="h4">Dispatch Summary</Typography>
    
          {loadingInstructionDetailsData &&
          loadingInstructionDetailsData.loadinginstruction ? (
            <Stack spacing={2}>
              <Stepper orientation="vertical" activeStep={activeStep}>
                <Step>
                  <StepLabel>
                    <Typography variant="h6">Dispatchs</Typography>
                  </StepLabel>
                  <StepContent>
                    <Card sx={{ marginTop: 2 }}>
                      <TableContainer sx={{ overflow: "unset" }}>
                        <Table sx={{ minWidth: 800 }}>
                          <TableHead>
                            <TableRow>
                              <TableCell>ID</TableCell>
                            </TableRow>
                          </TableHead>
                          <TableBody>
                            {loadingInstructionDetailsData.loadinginstruction.map(
                              (loadinginstruction, index) => (
                                <TableRow key={index}>
                                  <TableCell>{loadinginstruction.id}</TableCell>
                                </TableRow>
                              )
                            )}
                          </TableBody>
                        </Table>
                      </TableContainer>
                    </Card>
                    <Button
                      variant="contained"
                      style={{
                        marginTop: "10px",
                      }}
                      onClick={handleStepChange}
                    >
                      {activeStep === lastStepIndex ? "Finish" : "Continue"}
                    </Button>
                  </StepContent>
                </Step>
                <Step>
                  <StepLabel>
                    <Typography variant="h6">Order</Typography>
                  </StepLabel>
                  <StepContent>
                    <Card sx={{ marginTop: 2 }}>
                      <TableContainer sx={{ overflow: "unset" }}>
                        <Table sx={{ minWidth: 800 }}>
                          <TableHead>
                            <TableRow>
                              <TableCell>ID</TableCell>
                            </TableRow>
                          </TableHead>
                          <TableBody>
                            {loadingInstructionDetailsData.loadinginstruction.map(
                              (loadinginstruction, index) => (
                                <TableRow key={index}>
                                  <TableCell>{loadinginstruction.id}</TableCell>
                                </TableRow>
                              )
                            )}
                          </TableBody>
                        </Table>
                      </TableContainer>
                    </Card>
                    <Button
                      variant="contained"
                      style={{
                        marginTop: "10px",
                      }}
                      onClick={handleStepChange}
                    >
                      {activeStep === lastStepIndex ? "Finish" : "Continue"}
                    </Button>
                  </StepContent>
                </Step>
                <Step>
                  <StepLabel>
                    <Typography variant="h6">Tender</Typography>
                  </StepLabel>
                  <StepContent>
                    <Card sx={{ marginTop: 2 }}>
                      <TableContainer sx={{ overflow: "unset" }}>
                        <Table sx={{ minWidth: 800 }}>
                          <TableHead>
                            <TableRow>
                              <TableCell>ID</TableCell>
                            </TableRow>
                          </TableHead>
                          <TableBody>
                            {loadingInstructionDetailsData.loadinginstruction.map(
                              (loadinginstruction, index) => (
                                <TableRow key={index}>
                                  <TableCell>{loadinginstruction.id}</TableCell>
                                </TableRow>
                              )
                            )}
                          </TableBody>
                        </Table>
                      </TableContainer>
                    </Card>
                    <Button
                      variant="contained"
                      style={{
                        marginTop: "10px",
                      }}
                      onClick={handleStepChange}
                    >
                      {activeStep === lastStepIndex ? "Finish" : "Continue"}
                    </Button>
                  </StepContent>
                </Step>
              </Stepper>
            </Stack>
          ) : (
            <Typography variant="h10">Dispatch details data is null</Typography>
          )}
        </Container>
      );
    };
    

    You can see this example too: https://mui.com/material-ui/react-stepper/#vertical-stepper

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search