逻辑错误:双击转至下一步

问题描述 投票:0回答:1

我有一个问题,我有一个包含多个步骤的表单。每个步骤之间都有一个

Continue
Back
按钮,用于在步骤之间来回转换。但是,对于
Continue
按钮,在所有必填字段均已填写的情况下,需要双击才能向前移动。

步骤1.txs

interface Step1Props {
  onValidationChange: (isValid: boolean) => void;
  setErrorMessage: (message: string) => void;
  hasAttempted1Continue: boolean;
}

interface FormData {
  location?: string;
  title?: string;
  category?: string;
}

const Step1: React.FC<Step1Props> = ({
  onValidationChange,
  setErrorMessage,
  hasAttempted1Continue,
}) => {
   const [formData, setFormData] = useState<FormData>({});
   const [errors, setErrors] = useState<{ [key: string]: string }>({});

  useEffect(() => {
    if (hasAttempted1Continue) {
      const newErrors: { [key: string]: string } = {};
      if (!formData.title) newErrors.title = "Campaign title is required.";
      if (!formData.location) newErrors.location = "Location is required.";
      if (!formData.category) newErrors.category = "Category is required.";
      

      setErrors(newErrors);
      const isValid = Object.keys(newErrors).length === 0;
      onValidationChange(isValid);

      if (!isValid) {
        setErrorMessage(
          // "Please fix the following errors: " +
            Object.values(newErrors).join(", "),
        );
      } else {
        setErrorMessage("");
      }
    }
  }, [
    formData,
    onValidationChange,
    setErrorMessage,
    hasAttempted1Continue,
  ]);

return (
    <div className="flex flex-col gap-y-[30px] pb-[10px] pt-[10px]">
        <CardButtonInput
            placeholder={t("title")}
            type="text"
            name="title"
            value={formData.title}
            onChange={handleInputChange}
            error={errors["title"]}
        />
        <Radio
            options={cities}
            name="location"
            placeholder={t("location")}
            value={formData.location}
            onChange={handleLocationChange}
            error={errors["location"]}
            float={true}
        />
        <Radio
            options={campaignCategory}
            name="category"
            placeholder={"Category"}
            value={formData.category}
            onChange={handleCategoryChange}
            error={errors["cateory"]}
            float={true}
        />
    </div>
)

主要.tsx

Const Main = () => {
    const [currentStep, setCurrentStep] = useState(1);
    const [isStep1Valid, setIsStep1Valid] = useState(false); 
    const [errorMessage, setErrorMessage] = useState<string | null>(null);
    const [hasAttempted1Continue, sethasAttempted1Continue] = useState(false);

    const handleContinue = async () => {
    if (currentStep === 1) {
      sethasAttempted1Continue(true);
      if (!isStep1Valid) {
        setErrorMessage("Please complete the information before continuing..");
        return;
      }

      if (currentStep === 2) {
      sethasAttempted2Continue(true);
      if (!isStep2Valid) {
        setErrorMessage("Please complete the information before continuing..");
        return;
      }

      try {
        //CallAPI() + payload
      } catch (error) {
        setErrorMessage("Failed to submit the form. Please try again.");
        return;
      }
    } else {
      setCurrentStep((prevStep) =>
        Math.min(prevStep + 1, StepItems.length + 1),
      );
      window.scrollTo({
        top: 0,
        behavior: "smooth",
      });
    }
    setErrorMessage(null);
    }

const getStepItems = () => {
    const commonSteps = [
      {
        statusDefault: "default",
        statusVerified: "verified",
        statusUnverified: "unverified",
        personalInformation: t("step1"),
        numberOfSteps: 1,
      },
      {
        statusDefault: "default",
        statusVerified: "verified",
        statusUnverified: "unverified",
        personalInformation: t("step2"),
        numberOfSteps: 2,
      },
        ...
    ];

    return commonSteps.map((step, index) => {
      if (index + 1 < currentStep) {
        return { ...step, status: "verified" };
      } else if (index + 1 === currentStep) {
        return { ...step, status: "unverified" };
      }
      return { ...step, status: "" };
    });
  };
    ...
    return (
       <div className="flex flex-row items-center justify-center">
        {StepItems.map((card, index) => (
          <React.Fragment key={index}>
            <CardStep
              status={card.status}
              statusDefault={card.statusDefault}
              statusVerified={card.statusVerified}
              statusUnverified={card.statusUnverified}
              personalInformation={card.personalInformation}
              numberOfSteps={card.numberOfSteps}
            />
            {index < StepItems.length - 1 && (
              <div className="mb-20 flex flex-row items-center justify-center">
                <div className="h-[5px] w-[5px] rounded-full"></div>
                <div className="w-[150px] border-t border-[#9F76FF]"></div>
                <div className="h-[5px] w-[5px] rounded-full"></div>
              </div>
            )}
          </React.Fragment>
        ))}
      </div>
      {currentStep === 1 && (
        <Step1
          onValidationChange={setIsStep1Valid}
          setErrorMessage={setErrorMessage}
          hasAttempted1Continue={hasAttempted1Continue}
        />
      )}
      {currentStep === 2 && (
        <Step2
          onValidationChange={setIsStep2Valid}
          setErrorMessage={setErrorMessage}
          hasAttempted2Continue={hasAttempted2Continue}
        />
      )}
      {currentStep === 3 && <Step3 />}
      {currentStep === 4 && <Step4 />}
      <div className="flex flex-row items-center justify-center gap-x-[20px]">
        <CardButton
          text={t("back")}
          border="border-[#9F76FF]"
          color="text-[#9F76FF]"
          bg="bg-transparent"
          onClick={handleBack}
        />

        <CardButton
          text={t("continue")}
          onClick={handleContinue}
        />
      </div> 
    )
}

经过一段时间的调试,我发现在

handleContinue()
Main.tsx
中,return语句导致了逻辑。这意味着,如果我注释掉该行,即使在表单中检测到错误,单击“继续”也将允许我转到步骤 2。

我确实知道

return
的目的是在检测到错误时中断进入步骤 2 的过程。但即使所有必需的数据都已填写,它也会阻止我进入下一步。

我希望,当所有必填字段完成后,单击

Continue
按钮将使客户进入下一步。我该如何解决这个问题?

typescript next.js logic
1个回答
0
投票

你所做的事情并不真实。这就是我的做法。

import React, { ReactElement, useState, useMemo, useCallback } from 'react';

export function useMultiStepForm<C>(
  steps: { component: ReactElement; label: string }[],
  defaultData?: Partial<C>
) {
  const [currentStepIndex, setCurrentStepIndex] = useState(0);
  const [stepsData, setStepsData] = useState<Partial<C> | undefined>(
    defaultData
  );

  const next = useCallback(() => {
    setCurrentStepIndex((i) => {
      if (i >= steps.length - 1) return i;
      return i + 1;
    });
  }, [steps.length]);

  function back() {
    setCurrentStepIndex((i) => {
      if (i <= 0) return i;
      return i - 1;
    });
  }

  function goTo(index: number) {
    setCurrentStepIndex(index);
  }
  const stepComponents = useMemo(
    () =>
      steps.map((stepComponent, index) => {
        return React.cloneElement(stepComponent.component, {
          key: index,
          onNext: next,
          stepsData,
          isActive: currentStepIndex === index,
          setStepsData,
        });
      }),
    [steps, next, currentStepIndex, stepsData]
  );

  return {
    currentStepIndex,
    step: stepComponents[currentStepIndex],
    steps: stepComponents,
    originalSteps: steps,
    isFirstStep: currentStepIndex === 0,
    isLastStep: currentStepIndex === steps.length - 1,
    goTo,
    next,
    back,
  };
}

成分:

import React from 'react';

import AdditionalInfo from '@/components/ui/PropertyForm/Form/AdditionalInfo';
import BasicInfo from '@/components/ui/PropertyForm/Form/BasicInfo';
import Images from '@/components/ui/PropertyForm/Form/Images';
import LocationInfo from '@/components/ui/PropertyForm/Form/LocationInfo';
import { useMultiStepForm } from '@/hooks/useMultiStepForm';
import { PropertyType } from '@/types';

import StepNavigation from './StepNavigation';
import Videos from './Videos';
import VisitingTimeInfo from './VisitingTimeInfo';

const placeHolderFn = () => {};
export default function Form({
  defaultValues,
}: {
  defaultValues?: PropertyType;
}) {
  const { currentStepIndex, step, goTo, originalSteps } = useMultiStepForm<any>(
    [
      {
        component: (
          <BasicInfo
            stepsData={{}}
            onNext={placeHolderFn}
            setStepsData={placeHolderFn}
            key={'basic-info'}
            defaultValues={defaultValues}
          />
        ),
        label: 'Basic Info',
      },
      //NOTE landlord is not allowed to edit location
      ...(defaultValues
        ? []
        : [
            {
              component: (
                <LocationInfo
                  stepsData={{}}
                  key={'location'}
                  onNext={placeHolderFn}
                  setStepsData={placeHolderFn}
                  defaultValues={defaultValues}
                />
              ),
              label: 'Location',
            },
          ]),
      {
        component: (
          <AdditionalInfo
            stepsData={{}}
            key={'availability-and-amenities'}
            onNext={placeHolderFn}
            setStepsData={placeHolderFn}
            defaultValues={defaultValues}
          />
        ),
        label: 'Additional Info',
      },
      {
        component: (
          <VisitingTimeInfo
            stepsData={{}}
            key={'visiting-times'}
            onNext={placeHolderFn}
            setStepsData={placeHolderFn}
            defaultValues={defaultValues}
          />
        ),
        label: 'VISIT TIMES',
      },

      {
        component: (
          <Images
            stepsData={{}}
            onNext={placeHolderFn}
            setStepsData={placeHolderFn}
            key={'images'}
            defaultValues={defaultValues}
          />
        ),
        label: 'Images',
      },
      {
        component: (
          <Videos
            stepsData={{}}
            onNext={placeHolderFn}
            setStepsData={placeHolderFn}
            key={'videos'}
            defaultValues={defaultValues}
          />
        ),
        label: 'Videos',
      },
    ]
  );

  return (
    <div>
      <StepNavigation
        allowNavigationOnClick={!!defaultValues}
        currentStepIndex={currentStepIndex}
        steps={originalSteps}
        goTo={goTo}
        isEditing={!!defaultValues}
      />
      <div>{step}</div>
    </div>
  );
}

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.