导航栏重新渲染问题

时间:2021-03-05 09:44:58

标签: javascript reactjs navigation react-navigation

一般信息

我在重新呈现我的侧菜单时遇到了问题。我似乎找不到不让侧菜单重新呈现和覆盖我分配给它的数据的解决方案。

我在这个项目中使用 Gatsby。

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

我正在使用一个常规的 useState 钩子,我正在使用 onClick 函数分配新值:

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

问题

我遇到的问题是我的导航栏正在重新呈现,因为我要导航到另一个页面 onClick。我正在为钩子分配新值,但它被默认值覆盖,默认值在呈现新页面时页面顶部未定义。我的目标是能够根据站点是否有子页面进行条件渲染,这是不可能的,因为重新渲染后这些值将始终未定义。

导航栏组件在 page.js 中呈现,它通过 web 应用程序构建所有页面。 page.js 看起来像这样:

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;

问题

  • 有什么方法可以只渲染我的导航栏一次,这样我就可以在我点击新页面时控制渲染的内容吗?

非常感谢所有答案,我们已经为此工作了两个多星期,但进展甚微。

谢谢!

1 个答案:

答案 0 :(得分:0)

我的猜测是您在每个页面中都声明了导航栏,对吗? 并且您的导航栏不会重新渲染,而是被销毁和重新创建。 改为在路由器外部声明导航栏。这样它就会保持活力,一切都会正常进行。

编辑: 如果你想保持你的结构,你需要做的是将 activeParent 状态移动到导航栏之外,直到根组件,并将其作为道具传递。这样,当您在不同页面之间移动时,状态将保持不变。