reactjs 生产中React Joyride出现问题无法读取未定义的属性(阅读“0”)

nqwrtyyt  于 2022-12-29  发布在  React
关注(0)|答案(1)|浏览(184)

我们决定在我们的应用程序上实现一个简单的入门教程,在本地一切都很顺利,但一旦我们将其部署到生产环境中,它就会崩溃,并在devtools上显示下一个错误:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '0')

很难对此进行调试并找出问题所在,因为它是在生产环境中引起的,就像是闭着眼睛进行调试一样。
控制台显示的错误/错误是未定义的,逻辑也会在本地崩溃,但事实并非如此
该错误是在我们通过第一步后导致的,如您在此视频中所见(您还可以看到它是如何在本地工作的:VIDEO WITH THE ISSUE
他们的方式,其实施的joyride包括两个大键,第一个它的joyride wrapper

import { useEffect, useState } from 'react';
import Joyride, { CallBackProps, STATUS, Step } from 'react-joyride';
import { Tooltip } from './components/tool-tip';
import { OnboardingTourJoyrideProps, ValidSteps } from '../../types/onboarding-tour';
import { useGuidedTour } from '../../hooks/use-guided-tour';

export function OnboardingTourJoyride({ start, stepToCheck }: OnboardingTourJoyrideProps): JSX.Element {
  const { dashBoardSteps, terminalAppSteps, cloudAppSteps } = useGuidedTour();

  const [steps, setSteps] = useState<Step[]>(dashBoardSteps);
  const [run, setRun] = useState<boolean>(false);
  const [resetTour, setResetTour] = useState<boolean>(false);
  const [stepToInitRestart, setStepToInitRestart] = useState<number>(0);

  function handleSteps() {
    switch (stepToCheck) {
      case ValidSteps.DASHBOARD_STEPS:
        setSteps(dashBoardSteps);
        setStepToInitRestart(dashBoardSteps.length - 1);
        break;
      case ValidSteps.TERMINAL_APP_STEPS:
        setSteps(terminalAppSteps);
        setStepToInitRestart(terminalAppSteps.length - 1);
        break;
      case ValidSteps.CLOUD_APP_STEPS:
        setSteps(cloudAppSteps);
        setStepToInitRestart(cloudAppSteps.length - 1);
    }
  }

  useEffect(() => {
    const onboardinIsCompletedOrSkipped = handleCheckIfTourIsComplete();
    if (!onboardinIsCompletedOrSkipped) {
      handleSteps();
      if (start) setRun(true);
    }
  }, [start]);

  useEffect(() => {
    if (resetTour) {
      setRun(true);
      setResetTour(false);
    }
  }, [resetTour]);

  function handlePropertyToSaveOnLocalStorage() {
    switch (stepToCheck) {
      case ValidSteps.DASHBOARD_STEPS:
        localStorage.setItem('ONBOARDING_TOUR_DASHBOARD', 'true');
        break;
      case ValidSteps.TERMINAL_APP_STEPS:
        localStorage.setItem('ONBOARDING_TOUR_TERMINAL_APP', 'true');
        break;
      case ValidSteps.CLOUD_APP_STEPS:
        localStorage.setItem('ONBOARDING_TOUR_CLOUD_APP', 'true');
        break;
    }
  }

  function handleCheckIfTourIsComplete() {
    if (stepToCheck === ValidSteps.DASHBOARD_STEPS) {
      return localStorage.getItem('ONBOARDING_TOUR_DASHBOARD');
    } else if (stepToCheck === ValidSteps.TERMINAL_APP_STEPS) {
      return localStorage.getItem('ONBOARDING_TOUR_TERMINAL_APP');
    } else if (stepToCheck === ValidSteps.CLOUD_APP_STEPS) {
      return localStorage.getItem('ONBOARDING_TOUR_CLOUD_APP');
    }
  }

  function handleJoyrideCallback(data: CallBackProps) {
    const { status, action, index } = data;
    console.log(data);
    const finishedStatuses: string[] = [STATUS.FINISHED, STATUS.SKIPPED];

    if (index === stepToInitRestart && status === STATUS.SKIPPED) {
      setRun(false);
      setResetTour(true);
    }

    if (finishedStatuses.includes(status)) {
      if (action === 'skip') {
        setRun(false);
        handlePropertyToSaveOnLocalStorage();
      }
      setRun(false);
      handlePropertyToSaveOnLocalStorage();
    }
  }

  return (
    <Joyride
      tooltipComponent={Tooltip}
      disableScrolling={true}
      callback={handleJoyrideCallback}
      continuous
      hideCloseButton
      run={run}
      scrollToFirstStep
      showProgress={false}
      showSkipButton={true}
      steps={steps}
      styles={{
        options: {
          zIndex: 10000,
        },
      }}
    />
  );
}

它是一个简单的 Package 器,包含在应用程序中重用相同组件的所有逻辑
另一个是自定义工具提示组件:

import { Box, CloseButton, Flex, Text } from '@chakra-ui/react';
import { TooltipRenderProps } from 'react-joyride';
import { Button } from '../../button';
import { useIntl } from 'react-intl';

export function Tooltip({
  backProps,
  continuous,
  index,
  isLastStep,
  primaryProps,
  skipProps,
  step,
  tooltipProps,
  size,
}: TooltipRenderProps): JSX.Element {
  const intl = useIntl();

  const steps = {
    currentStep: index,
    stepsLength: size - 2,
  };

  function handleResetOrBackStep(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
    if (isLastStep) {
      skipProps.onClick(e);
    } else {
      backProps.onClick(e);
    }
  }

  function handleCloseButton(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
    if (isLastStep) {
      primaryProps.onClick(e);
    } else {
      skipProps.onClick(e);
    }
  }

  function handleFowardButton() {
    return continuous
      ? index !== 0 && !isLastStep
        ? intl.formatMessage({ id: 'buttons.next' })
        : isLastStep
        ? intl.formatMessage({ id: 'buttons.finish' })
        : intl.formatMessage({ id: 'buttons.startTour' })
      : null;
  }

  function handleShowStepsCounter() {
    return index !== 0 && !isLastStep ? (
      <Text fontSize="16px">
        {intl.formatMessage(
          { id: 'onboardingTour.toolTip.stepsCounter' },
          {
            currentStep: steps.currentStep,
            totalSteps: steps.stepsLength,
          },
        )}
      </Text>
    ) : (
      !isLastStep && (
        <Button variant="outline" {...skipProps}>
          {intl.formatMessage({ id: 'buttons.skipTour' })}
        </Button>
      )
    );
  }

  function handleBackwardButton() {
    return isLastStep
      ? intl.formatMessage({ id: 'buttons.restartTour' })
      : intl.formatMessage({ id: 'buttons.previous' });
  }

  return (
    <Box {...tooltipProps} background="white" p="48px" w="100%" borderRadius="6px">
      <Box padding="md">
        <Flex justifyContent="space-between" align="baseline" marginBottom="15px">
          {step.title && (
            <Text fontSize="20px" fontWeight="700">
              {step.title}
            </Text>
          )}
          <CloseButton onClick={e => handleCloseButton(e)} />
        </Flex>
        {step.content && (
          <Box>
            <Text w="504px" fontSize="16px" fontWeight="400" lineHeight="26px" marginBottom="48px">
              {step.content}
            </Text>
          </Box>
        )}
      </Box>
      <Box>
        <Flex justifyContent="space-between" align="center">
          {handleShowStepsCounter()}
          <Flex w={isLastStep ? '100%' : ''} justifyContent="space-between">
            {index !== 0 && (
              <Button marginRight="12px" variant="outline" onClick={e => handleResetOrBackStep(e)}>
                {handleBackwardButton()}
              </Button>
            )}
            <Button h="35px" {...primaryProps}>
              {handleFowardButton()}
            </Button>
          </Flex>
        </Flex>
      </Box>
    </Box>
  );
}

我不知道是否有人有过类似的经历,我在谷歌上搜索了所有的SO和库存储库中的问题。还有一点很奇怪,因为在我使用react-joyride并部署到生产环境中时,没有任何问题。为了让大家了解上下文,我们使用了一个名为Gasket的框架next。

z4iuyo4d

z4iuyo4d1#

有同样的问题。这里是解决方案-https://github.com/gilbarbara/react-joyride/issues/857(也更新nextjs到13. 1. 1修复了这个问题)

相关问题