-1

我正在尝试集成CleverTap到我的Next.js应用程序中。遵循文档Web SDK 快速入门指南,但面临问题:

服务器错误 ReferenceError: 窗口未在 Next.js 中定义

请看一看


_app.tsx

import React, { useEffect, useState } from "react";
import type { AppProps } from "next/app";
import { appWithTranslation } from "next-i18next";
import { Hydrate, QueryClient, QueryClientProvider } from "react-query";
import { ReactQueryDevtools } from "react-query/devtools";

import nextI18NextConfig from "../next-i18next.config.js";

import "tailwindcss/tailwind.css";
import "styles/globals.scss";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
import { useRouter } from "next/router";
import SvgPageLoading from "components/color-icons/PageLoading";
// import { PageLoading } from "components/color-icons/";

import { DefaultSeo } from 'next-seo';
import SEO from 'next-seo.config';
import {cleverTap} from "utils/cleverTapHelper";

cleverTap.initialize('TEST-61c-a12');

function MyApp({ Component, pageProps }: AppProps) {
  const [queryClient] = React.useState(
    () =>
      new QueryClient({
        defaultOptions: {
          queries: {
            refetchOnWindowFocus: false,
            staleTime: Infinity,
          },
        },
      })
  );
  const router = useRouter();
  const [isAnimating, setIsAnimating] = useState(false);
  useEffect(() => {
    const handleStart = () => {
      setIsAnimating(true);
    };
    const handleStop = () => {
      setIsAnimating(false);
    };

    router.events.on("routeChangeStart", handleStart);
    router.events.on("routeChangeComplete", handleStop);
    router.events.on("routeChangeError", handleStop);

    return () => {
      router.events.off("routeChangeStart", handleStart);
      router.events.off("routeChangeComplete", handleStop);
      router.events.off("routeChangeError", handleStop);
    };
  }, [router]);
  return (
    <QueryClientProvider client={queryClient}>
      <Hydrate state={pageProps.dehydratedState}>
        <DefaultSeo {...SEO} />
        <Component {...pageProps} />
        {isAnimating && (
          <div className="fixed top-0 left-0 flex items-center justify-center w-screen h-screen overflow-visible bg-white bg-opacity-80 z-overlay top-z-index">
            <SvgPageLoading />
          </div>
        )}
        <ReactQueryDevtools initialIsOpen={false} />
      </Hydrate>
    </QueryClientProvider>
  );
}

export default appWithTranslation(MyApp, nextI18NextConfig);

cleverTapHelper.ts

export const cleverTap = {
    initialize: function (accountId) {
        console.log('I see initialize req')
        window.clevertap = {event: [], profile: [], account: [], onUserLogin: [], notifications: []};
        window.clevertap.account.push({'id': accountId});
        (function () {
            var wzrk = document.createElement('script');
            wzrk.type = 'text/javascript';
            wzrk.async = true;
            wzrk.src = ('https:' == document.location.protocol ? 'https://d2r1yp2w7bby2u.cloudfront.net' : 'http://static.clevertap.com') + '/js/a.js';
            var s = document.getElementsByTagName('script')[0];
            s.parentNode.insertBefore(wzrk, s);
        })();
    },

    event: function (name, payload = {}) {
        console.log('I see event req')
        if (payload) {
            window.clevertap.event.push(name, payload);
        } else {
            window.clevertap.event.push(name);
        }

    },

    profile: function (payload) {
        console.log('I see profile req')
        window.clevertap.profile.push(payload);
    },

    logout: function () {
        console.log('I see logout req')
        window.clevertap.logout();
    }
};

cleverTap.d.ts

declare global {
    interface Window {
        clevertap: any;
    }
}

export {};

Window对象不应该是undefined不确定的!这是怎么回事?

4

1 回答 1

1

这是因为 NextJS 试图在服务器上执行该功能,因为它使用 SSR,并且window是一个浏览器对象。由于该window对象仅在浏览器(客户端)中可用,因此服务器无法识别该window对象,因此获取undefined. 为了解决这个问题,您应该确保包含客户端相关代码的任何功能/组件仅在浏览器或客户端上执行。一种方法是使用诸如useEffect仅在安装组件后运行的钩子。另一种方法是使用几乎做同样事情的延迟加载。

  1. 使用useEffect钩子。在您的_app.tsx组件中,添加一个新useEffect钩子并将初始化代码移动到新创建的useEffect函数中。
useEffect(()=>{
  cleverTap.initialize('TEST-61c-a12');
},[])
  1. 使用延迟加载。(动态导入)不是直接导入函数,而是动态导入并将服务器端渲染设置为false
import dynamic from 'next/dynamic'

const cleverTap = dynamic(()=>{
  return import("utils/cleverTapHelper")
},
{ssr:false}
)

cleverTap.initialize('TEST-61c-a12');
于 2021-12-19T13:15:15.013 回答