【问题标题】:Page Templates re-rendering on every click in Prismic & Gatsby在 Prismic 和 Gatsby 中每次点击都会重新渲染页面模板
【发布时间】:2021-02-16 11:58:36
【问题描述】:

我一直在尝试诊断为什么我在单击 <Link> 组件时多次运行 useEffect,即使依赖项为空。我找到了一个很好的方法来找出我的问题所在,使用this answer.中的解决方案

基本上,我添加了一个 useEffectconsole 记录组件重新渲染,然后我一直向上爬,直到找到不会重新渲染的最高级别组件。

useEffect(()=>{
  console.log('this component is rendered');
},[]);

我正在使用gatsby-plugin-layout,而我的AppLayout 组件是不会发生重新渲染的组件,这意味着问题出在我的页面模板中,正如gatsby-source-prismic-graphql 中定义的那样,这是下一个单击<Link>console 记录页面更改的树下的东西。综上所述,我不完全确定问题出在哪里,或者我的AppLayoutgatsby-config.js 中是否有什么东西会抛出它并导致这种行为发生。我该如何解决它,这样我的页面就不会不断地重新渲染?下面包括我的AppLayoutgatsby-config.js

提前致谢。

gatsby-config.js

/* eslint-disable @typescript-eslint/camelcase */
const path = require('path');

require('dotenv').config({
  path: `.env.${process.env.NODE_ENV}`,
});

const site = require('./config/site');

const pathPrefix = site.pathPrefix === '/' ? '' : site.pathPrefix;

module.exports = {
  pathPrefix: site.pathPrefix,
  siteMetadata: {
    siteUrl: site.url + pathPrefix,
    pathPrefix,
    title: site.title,
    titleAlt: site.titleAlt,
    titleTemplate: site.titleTemplate,
    description: site.description,
    banner: site.logo,
    headline: site.headline,
    siteLanguage: site.siteLanguage,
    ogLanguage: site.ogLanguage,
    author: site.author,
    twitter: site.twitter,
    facebook: site.facebook,
  },
  plugins: [
    'gatsby-plugin-react-helmet-async',
    'gatsby-plugin-typescript',
    'gatsby-plugin-sharp',
    'gatsby-plugin-sitemap',
    'gatsby-transformer-sharp',
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'images',
        path: path.join(__dirname, `src`, `assets`, `images`),
      },
    },
    {
      resolve: 'gatsby-plugin-manifest',
      options: {
        name: 'one-day-doors-and-closets',
        short_name: 'starter',
        start_url: '/',
        background_color: '#663399',
        theme_color: '#663399',
        display: 'minimal-ui',
        icon: 'src/assets/images/icon.png',
      },
    },
    {
      resolve: '@sentry/gatsby',
      options: {
        dsn: process.env.SENTRY_DSN,
        enabled: (() => ['production'].indexOf(process.env.NODE_ENV) !== -1)(),
      },
    },
    {
      resolve: 'gatsby-plugin-react-svg',
      options: {
        rule: {
          include: path.resolve(__dirname, 'src/assets/svg'),
        },
      },
    },
    {
      resolve: 'gatsby-source-prismic-graphql',
      options: {
        repositoryName: `${process.env.PRISMIC_REPOSITORY_NAME}`,
        defaultLang: 'en-us',
        path: '/preview',
        previews: false,
        accessToken: `${process.env.PRISMIC_ACCESS_TOKEN}`,
        pages: [
          {
            type: 'Homepage',
            match: '/',
            component: require.resolve('./src/pages/index.tsx'),
          },
          {
            type: 'Landing',
            match: '/:uid',
            component: require.resolve('./src/templates/landing.tsx'),
          },
          {
            type: 'Legal',
            match: '/:uid',
            component: require.resolve('./src/templates/legal.tsx'),
          },
          {
            type: 'Locator',
            match: '/:uid',
            component: require.resolve('./src/pages/locations.tsx'),
          },
          {
            type: 'Product',
            match: '/products/:uid',
            component: require.resolve('./src/templates/product.tsx'),
          },
        ],
      },
    },
    {
      resolve: 'gatsby-plugin-layout',
      options: {
        component: require.resolve('./src/components/app-layout/AppLayout.tsx'),
      },
    },
  ],
};

AppLayout.tsx

import React, { ReactNode, useEffect, useState } from 'react';

import { Devtools } from 'components/devtools/Devtools';
import { Footer } from 'components/footer/Footer';
import { Header } from 'components/header/Header';
import { NavigationSkipLink } from 'components/navigation-skip-link/NavigationSkipLink';
import { AppContext } from 'contexts/app-context/AppContext';
import { graphql, StaticQuery } from 'gatsby';
import { usePrevious } from 'hooks/use-previous';
import { TransitionGroup, CSSTransition } from 'react-transition-group';

import s from './AppLayout.scss';

interface AppLayoutProps {
  props: any;
  children: ReactNode;
  location: any;
}

const isDev = process.env.NODE_ENV === 'development';

export const MainContentId = 'maincontent';
export const timeout = 250;

const NavQuery = graphql`
  query NavQuery {
    prismic {
      allNavigations {
        edges {
          node {
            ...NotificationBar
            ...NavigationItems
            ...FooterNavigationItems
            ...LegalNavigationItems
          }
        }
      }
    }
  }
`;

// eslint-disable-next-line react/display-name
export default ({ children, location: { pathname } }: AppLayoutProps) => {
  const [fadeEffectVisible, setFadeEffectVisible] = useState(false);
  const [page, setPage] = useState(pathname);
  const prevPage = usePrevious(pathname);

  useEffect(
    () => () => {
      if (pathname !== prevPage) {
        setFadeEffectVisible(true);
        setPage(page);
      }
    },
    [pathname],
  );

  const handleFadeEffectEntered = () => {
    setTimeout(() => {
      setFadeEffectVisible(false);
    }, 50);
  };

  return (
    <StaticQuery
      query={`${NavQuery}`}
      render={(data) => (
        <>
          <AppContext>
            <CSSTransition
              in={fadeEffectVisible}
              timeout={timeout}
              classNames={{
                enter: s.fadeEffectEnter,
                enterActive: s.fadeEffectEnterActive,
                enterDone: s.fadeEffectEnterDone,
                exit: s.fadeEffectExit,
                exitActive: s.fadeEffectExitActive,
              }}
              onEntered={handleFadeEffectEntered}
            >
              <div className={s.fadeEffect} aria-hidden="true" />
            </CSSTransition>

            <NavigationSkipLink />
            <Header navigationContent={data.prismic.allNavigations.edges[0].node} />
            <TransitionGroup component={null}>
              <CSSTransition
                key={pathname}
                timeout={timeout}
                classNames={{
                  enter: s.pageEnter,
                }}
              >
                <div id={MainContentId} className={s.layout}>
                  {children}

                  <Footer navigationItems={data.prismic.allNavigations.edges[0].node} />

                  {isDev && <Devtools />}
                </div>
              </CSSTransition>
            </TransitionGroup>
          </AppContext>
        </>
      )}
    />
  );
};

【问题讨论】:

  • 很难从您分享的信息中看出原因(尽管已经很多了。)只是猜测,您是否尝试过将&lt;AppContext&gt; 下的所有内容分解为自己的组件并将其包装在一个React.memo?当上下文发生变化时,可能会导致其中的所有内容重新渲染。为了更好地调试,您可以尝试使用 React Devtool 记录站点的性能,单击一次链接并检查重新渲染的原因。
  • 你试过删除动画吗?
  • 我有。我认为 Derek 走在正确的轨道上,似乎与我的contexts 有关。正在调试它。
  • 好像和gatsby-source-prismic-graphql有关。迁移到现在 Prismic 推荐的 gatsby-source-prismic 似乎已经修复了。

标签: javascript reactjs gatsby use-effect prismic.io


【解决方案1】:

很难理解发生了什么,但是,我看到了您的 useEffect 代码

你的代码

useEffect(() => () => {
        if (pathname !== prevPage) {
            setFadeEffectVisible(true);
            setPage(page);
        }
    },
        [pathname],
    );

对此进行重构

useEffect(() => {
        if (pathname !== prevPage) {
            setFadeEffectVisible(true);
            setPage(page);
        }
    },
        [pathname],
    );

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-08
    • 1970-01-01
    • 2020-11-16
    • 2020-02-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多