Home > Net >  Closing sidebar crashes react application
Closing sidebar crashes react application

Time:07-14

I am currently working on a dashboard application in react.js. However, after adding some functionality to a child component involving the useState hook, the application crashes every time I close/open the sidebar in the parent component. This is the error i get:enter image description here

and this is the parent component:

import { Button } from "primereact/button";
import axios from "axios";
import { useContext, useState } from "react";
import { UserContext } from "../contexts/UserContext";
import { useNavigate } from "react-router-dom";
import { Sidebar } from "primereact/sidebar";
import { Divider } from "primereact/divider";
import { Avatar } from "primereact/avatar";
import { Menu } from "primereact/menu";
import "primeicons/primeicons.css";
import "../styling/page-home.css";
import Settings from "../components/dashboard/Settings";
import Stats from "../components/dashboard/Stats";

export default function PageHome() {


  const context = useContext(UserContext);

  const navigate = useNavigate();

  const dummyUser = {
    username: "Jane Doe",
    email: "[email protected]",
    image: "./media/avatar-picture.jpeg",
  };

  const [content, setContent] = useState(Settings);

  let menuItems = [
    { label: "Dashboard", icon: "pi pi-fw pi-th-large" },
    { label: "Planning", icon: "pi pi-fw pi-calendar" },
    { label: "Offertes", icon: "pi pi-fw pi-file" },
    { label: "Facturen", icon: "pi pi-fw pi-euro" },
    { label: "Webshop", icon: "pi pi-fw pi-shopping-bag" },
    { label: "Statistieken", icon: "pi pi-fw pi-chart-bar", command:() => {setContent(Stats)} },
  ];

  let settings = [{ label: "Settings", icon: "pi pi-fw pi-cog", command:() => {setContent(Settings)}  }];

  const logout = () => {
    axios.post(process.env.REACT_APP_API   "/auth/logout").then((res) => {
      if (res.data.msg === "ok") {
        context.logout();
        navigate("/login");
      }
    });
  };

  const [visible, setVisible] = useState(true);

  return (
    <>
      <div className="page-home">
        <Button icon="pi pi-arrow-right" onClick={(e) => setVisible(true)} />

        <Sidebar
          showCloseIcon={false}
          className="p-0 p-sidebar-sm border-none shadow-8 z-0"
          visible={visible}
          modal={false}
          onHide={() => setVisible(false)}
        >
          <div className="sidebar-container flex flex-column justify-content-between h-full">
            <div className="sidebar-container-top">
              <div
                id="logo-box"
                className="flex flex-row align-items-center gap-3 pl-2"
              >
                <Avatar image="./media/mbt-logo.jpeg" size="medium" />
                <h3 className="opacity-50">THAN GIFTS</h3>
              </div>
              <Divider className="opacity-30"/>
              {/*User card */}
              <div className="flex flex-row align-items-center gap-3 py-5 px-2">
                <Avatar
                  className="p-0"
                  image={dummyUser.image}
                  size="large"
                  shape="circle"
                />
                <div id="avatar-info">
                  <div className="font-bold" id="avatar-info-username">
                    {dummyUser.username}
                  </div>
                  <div className="text-sm opacity-40" id="avatar-info-email">
                    {dummyUser.email}
                  </div>
                </div>
              </div>
              <Menu className="border-none" model={menuItems} />
              <Divider className="opacity-30"/>
              <Menu className="border-none" model={settings} />
            </div>
            <Button
              className="p-button-secondary p-button-text"
              onClick={() => {
                setVisible(false);
              }}
            >
              {" "}
              <i className="pi pi-fw pi-window-minimize pr-4" />
              Toggle sidebar
            </Button>
          </div>
        </Sidebar>

        <div
          id="main-container"
          className="flex flex-row justify-content-center align-items-center z-1"
          legend={context.user_name}
          style={{ marginLeft: visible ? "20rem" : "0rem" }}
        >
          {content}
        </div>
      </div>
    </>
  );
}

And this is the child component:

import React from "react";
import { Card } from "primereact/card";
import { Password } from "primereact/password";
import { useState } from "react";
import { Fieldset } from "primereact/fieldset";
import { InputText } from "primereact/inputtext";

export default function Settings() {
  const [password, setPassword] = useState("");
  return (
    <Card title="Settings" className="w-full m-5">
      <Fieldset legend="Wachtwoord wijzigen">
        <div className="p-4">
          <h5>Huidig wachtwoord</h5>
          <Password value={password} onChange={(e)=>{setPassword(e.target.value)}} toggleMask feedback={false}/>

          <h5>nieuw wachtwoord</h5>
          <Password toggleMask />

          <h5>herhaal wachtwoord</h5>
          <Password toggleMask feedback={false}/>
        </div>
      </Fieldset>
    </Card>
  );
}

If anyone has any clue to what is throwing these errors and how to resolve them, I would be very happy to hear from you. :)

CodePudding user response:

The error occurs because you are doing:

 const [content, setContent] = useState(Settings);

and Settings is a component. When useState receives a function that returns a value this is called lazy initial state. In this case, react is trying to set the value that returns the Settings component as initial state of content, but not the component.

A simple way to fix this is:

const [Content, setContent] = useState(() => Settings);
//...
return (
//...
  {<Content />}

But is a bit weird to store components as state, i think that it would be better to use react-router or, if you only have a couple of possible contents, use a flag that indicates wich one has to be displayed.

  • Related