简体   繁体   中英

Navbar re-rendering issues

GENERAL INFO

I'm having trouble with the re-rendering of my sidemenu. I can't seem to find a solution to not make the sidemenu to re-render and override the data that I assign to it.

I'm using Gatsby in this project.

const [activeParent, setActiveParent] = useState({parentId: undefined, hasSubPages: undefined});

I'm using a regular useState hook that I'm assigning new values with an onClick function:

onClick={() => setActiveParent({parentId: item1._key, hasSubPages: item1?.subLink?.length > 0 ? true : false })}

THE ISSUE

The issue that I'm experiencing is that my navbar is being re-rendered since I'm navigating to another page onClick. I'm assigning new values to the hook but it gets overridden by the default values which is undefined at the top of the page when a new page is being rendered. My goal is to be able to make conditional rendering depending on if the site has sub pages or not and this is not possible since the values will always be undefined after the re-render.

The navbar component is rendered in the page.js which builds all the pages over the webapplication. The page.js looks like this:

import React from "react";
import { graphql } from "gatsby";

import { Container, Row, Col } from "react-bootstrap";

import Hero from "../components/cmsComponents/hero";
import LinkBoxes from "../components/cmsComponents/linkBoxes";
import BlockContent from "../components/cmsComponents/blockContent";
import LinkLister from "../components/cmsComponents/linkLister";
import SideMenu from "../components/sideMenu/sideMenu";
import FormBuilder from "../components/cmsComponents/formBuilder/formBuilder";

import GraphQLErrorList from "../components/graphql-error-list";
import SEO from "../components/seo";
import Layout from "../components/layout";

export const query = graphql`
  query PageTemplateQuery($id: String!) {
    sanityPage(id: { eq: $id }) {
      ...PageInfo
    }
    site: sanitySiteSettings(_id: { regex: "/(drafts.|)siteSettings/" }) {
      title
      openGraph {
        title
        description
        image {
          ...SanityImage
        }
      }
      image {
        asset {
          url
        }
      }
    }
  }
`;

const Page = (props) => {
  const { data, errors } = props;

  if (errors) {
    return (
      <Layout>
        <GraphQLErrorList errors={errors} />
      </Layout>
    );
  }

  const page = data.sanityPage || data.page;

  const content = (page._rawContent || [])
    .filter((c) => !c.disabled)
    .map((c, i) => {
      let el = null;
      switch (c._type) {
        case "hero":
          el = <Hero key={c._key} {...c} indexPage={props.indexPage} />;
          break;
        case "linkBoxes":
          el = <LinkBoxes key={c._key} {...c} />;
          break;
        case "blockText":
          el = <BlockContent key={c._key} {...c} />;
          break;
        case "linkList":
          el = <LinkLister key={c._key} {...c} />;
          break;
        case "formBuilder":
          el = <FormBuilder key={c._key} {...c} />;
          break;
        default:
          el = null;
      }
      return el;
    });

  // const menuItems = page.navMenu && (page.navMenu.items || []);
  // const pageTitle = data.route && !data.route.useSiteTitle && page.title;
  // const parent2 = (data.navMenu && page.navMenu.parentPage) || null;

  // Checks if a page has a parent page
  const parent = () => {
    if (
      page.navMenu &&
      page.navMenu.parentPage &&
      page.navMenu.parentPage.slug.current
    ) {
      return page.navMenu.parentPage;
    } else {
      return null;
    }
  };

  // Gives the index page a full width fluid bootstrap container and all other pages a regular bootstrap container
  const PageContainer = ({ children }) => {
    if (props.indexPage) {
      return (
        <Container fluid className="__p-0">
          {children}
        </Container>
      );
    } else {
      return <Container className="__p-0"> {children}</Container>;
    }
  };

  const openGraphData =
    props.data?.sanityPage?.openGraph || props.data.openGraph;

  return (
    <Layout parentPage={parent()}>
      <SEO title={page.title} openGraph={openGraphData} />
      {console.log("Page er:", page)}

      <PageContainer props={props}>
        <Row>
          {/* Loads side menu if a page is not the index page */}
          {page?.navMenu && !props.indexPage && (
            <Col md={4} lg={4} className="d-none d-md-block">
              <nav aria-label="local navigation" className="local-navigation">
                <SideMenu
                  props={page.navMenu}
                  parentPage={parent()}
                  location={props.location}
                />
              </nav>
            </Col>
          )}

          <Col className="p-0">
            <main>{content}</main>
          </Col>
        </Row>
      </PageContainer>
    </Layout>
  );
};

export default Page;

THE QUESTION

  • Are there any way to just render my navbar once so I can control what is being rendered when I click on a new page?

All answers are greatly appreciated, been working on this for over two weeks with minimal progress.

Thanks!

My guess is that you declare the Navbar in every page, right? And your Navbar is not rerendered but destroyed and recreated. Declare the navbar outside of the router instead. That way it will remain alive and everything will work.

Edit: If you want to keep your structure, what you need to do is to move the activeParent state outside of the navbar, up to the root component, and pass it down as props. That way the state will persist when you move between different pages.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM