Too many re-renders. React limits the number of renders to prevent an infinite loop in the component

when trying to capture the image its throwing an error, Too many re-renders
the function handleCapture is rendering too many times

const Survey: React.FC = () => {
  const dispatch = useDispatch();
  const navigate = useNavigate();
  const [currentStep, setCurrentStep] = useState(0);

  const [capturedPicture, setCapturePicture] = useState<string>('');
  const [showPopup, setShowPopup] = useState(false);
  const [popup, setPopup] = useState(false)
  const [loading, setLoading] = useState(false)
  const [enableGeolocation, setEnableGeolocation] = useState(false)
  const [locationFetched, setLocationFetched] = useState(false)
  const [isOnline, setIsOnline] = useState(navigator.onLine);
  const currentDate = getCurrentTimeStampOfEndMarket()
  const [selectDate, setselectDate] = useState(currentDate)

  const employeeDetails = useSelector((state: RootState) => state.jwtToken.jwtTokenData?.UserData);
  const imageCaptureLimit = 8;
  const newOutlet = useSelector((state: RootState) => state.newOutletSurvey.data);
  const surveyJson: SurveyDetail[] = newOutlet ? JSON.parse(newOutlet?.content!) : [];
  const memoizedSurveyJson = useMemo(() => surveyJson, [surveyJson]);

  const capturedImages = useSelector((state: RootState) =>
    state?.photo.data.filter(image => image.source !== 'Survey') ?? []
  );
  const [surveyResponses, setSurveyResponses] = useState<LocalSurveyResponse[]>([]);

  const [validationErrors, setValidationErrors] = useState<{ key: string; errorMessage: string; type: string; }[]>([]);

  useEffect(() => {
    return () => {
      dispatch(clearImage())
      setCapturePicture('');
    }
  }, []);



  useEffect(() => {
    if (capturedImages.length > 0) {
      setCapturePicture(capturedImages[capturedImages.length - 1].images);
    }
  }, [capturedImages]);

  const handleCapture = (imgSrc: string) => {
    try {
      const base64Image = imgSrc.replace(/^data:image/(png|jpeg);base64,/, '');
      setCapturePicture(base64Image);
      const data: PhotoModel = {
        source: "newOutletSurvey",
        images: base64Image
      };
      dispatch(addPhoto(data));
      setShowPopup(false);
    } catch (error) {
      console.error("Error in capturing image", error);
    }

  }


  const handleClick = () => {
    setShowPopup(true);
  };

  const closePopup = () => {
    setShowPopup(false);
  };

  const onRemoveClick = (index: number) => {
    dispatch(deleteImage(index));
  };

  const updateSurveyResponse = (questionId: string, response: LocalSurveyResponse) => {
    setSurveyResponses(prevState => {
      const existingIndex = prevState.findIndex(item => item.questionId === questionId);
      if (existingIndex !== -1) {
        return prevState.map((item, i) => (i === existingIndex ? response : item));
      } else {
        return [...prevState, response];
      }
    });
  };

  const handleSelectedDate = (date: { day: string; month: string; year: string }) => {
    const formattedDate = `${date.year}-${date.month}-${date.day}`;
    setselectDate(formattedDate);
  }

  const setSteps = (surveyData: SurveyDetail[]) => {
    const updatedSteps = surveyData.map((data, index) => {
      const questionId = `${data.type}_${index}`;
      switch (data.type) {
        case 'text':
          return (
            <div key={questionId}>
              <TextBox
                label={data.Label}
                placeholder={data.Placeholder}
                onPageChange={(text) => {
                  const newResponse: LocalSurveyResponse = {
                    questionId,
                    question: data.Label,
                    response: [text],
                    type: data.type,
                  };
                  updateSurveyResponse(questionId, newResponse);
                }}
              />
            </div>
          );
        case 'checkbox':
          return (
            <div key={questionId}>
              <Label Label={data.Label}>
                <div className="flex flex-wrap gap-2 overflow-y-scroll no-scrollbar">
                  {data.options && data.options.map((option, optionIndex) => (
                    <div key={optionIndex}>
                      <ButtonWithText
                        isEnabled={surveyResponses.find(r => r.questionId === questionId)?.response.includes(option)}
                        // isSelected={surveyResponses.find(r => r.questionId === questionId)?.response.includes(option)}
                        label={option}
                        onClick={() => {
                          const currentResponse = surveyResponses.find(r => r.questionId === questionId)?.response || [];
                          const newResponse: LocalSurveyResponse = {
                            questionId,
                            question: data.Label,
                            response: currentResponse.includes(option)
                              ? currentResponse.filter(item => item !== option)
                              : [...currentResponse, option],
                            type: data.type,
                          };
                          updateSurveyResponse(questionId, newResponse);
                        }}
                        type={'mini'}
                      />
                    </div>
                  ))}
                </div>
              </Label>
            </div>
          );
        case 'radio':
          return (
            <div key={questionId}>
              <Label Label={data.Label}>
                <div className="flex flex-wrap gap-2 overflow-y-scroll no-scrollbar">
                  {data.options && data.options.map((option, optionIndex) => (
                    <div key={optionIndex}>
                      <SurveyRadioButton
                        isEnabled={surveyResponses.find(r => r.questionId === questionId)?.response.includes(option)}
                        label={option}
                        onClick={() => {
                          const newResponse: LocalSurveyResponse = {
                            questionId,
                            question: data.Label,
                            response: [option],
                            type: data.type,
                          };
                          updateSurveyResponse(questionId, newResponse);
                        }}
                        type={'mini'}
                      />
                    </div>
                  ))}
                </div>
              </Label>
            </div>
          );
        case 'counter':
          return (
            <div key={questionId}>
              <Counter
                label={data.Label}
                value={parseInt(surveyResponses.find(r => r.questionId === questionId)?.response[0] || '0')}
                onCountChange={(newCount) => {
                  const newResponse: LocalSurveyResponse = {
                    questionId,
                    question: data.Label,
                    response: [newCount.toString()],
                    type: data.type,
                  };
                  updateSurveyResponse(questionId, newResponse);
                }}
              />
            </div>
          );
        case 'signature':
          return (
            <div key={questionId}>
              <Label Label={data.Label}>
                <SignatureCapture
                  onSave={(image) => {
                    const base64Image = image.replace(/^data:image/(png|jpeg);base64,/, '');
                    const newResponse: LocalSurveyResponse = {
                      questionId,
                      question: data.Label,
                      response: [base64Image],
                      type: data.type,
                    };
                    updateSurveyResponse(questionId, newResponse);
                  }}
                />
              </Label>
            </div>
          );
        case 'capture':
          return (
            <div className="w-full " key={questionId}>
              <Label Label={t("Upload")}>
                {capturedImages.length === 0 && (
                  <div
                    className="font-poppins-bold rounded-lg flex items-center justify-center w-full h-24"
                    onClick={() => handleClick()}
                  style={{ backgroundImage: "url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' rx='8' ry='8' stroke='black' stroke-width='2' stroke-dasharray='10' stroke-dashoffset='10' stroke-linecap='butt'/%3e%3c/svg%3e")" }}
                  >
                    <Icons.CAMERA_PLUS size={32} />
                  </div>
                )}
                <div className="w-full flex flex-wrap justify-space gap-3">
                  {capturedImages.length > 0 && capturedImages.length < imageCaptureLimit && (
                    <div
                      className="font-poppins-bold rounded-lg flex items-center justify-center bg-white w-24 h-24"
                      onClick={() => handleClick()}
                    >
                      <Icons.CAMERA_PLUS size={32} />
                    </div>
                  )}
                  {capturedImages.map((img: PhotoModel, i: number) => {
                    const newResponse: LocalSurveyResponse = {
                      questionId,
                      question: data.Label,
                      response: capturedImages.map(img => img.images),
                      type: data.type,
                    };
                    updateSurveyResponse(questionId, newResponse);
                    return (
                      <ButtonWithImage
                        onRemoveClick={() => onRemoveClick(i)}
                        imageUrl={`data:image//(png|jpeg|jpg);base64,${img.images}`}
                        alt={`Image ${i}`}
                        enableCloseButton={true}
                        key={i}
                      />
                    )
                  })}
                </div>
              </Label>
            </div>
          )
        case 'date':
          return (
            <div key={questionId}>
              <Label Label={data.Label}>

                <CalendarPicker
                  dateFormat="dd-mm-yyyy"
                  initialValue={currentDate}
                  onDateChange={(date) => {
                    handleSelectedDate(date);
                    const formattedDate = `${date.year}-${date.month}-${date.day}`;
                    const newResponse: LocalSurveyResponse = {
                      questionId,
                      question: data.Label,
                      response: [formattedDate],
                      type: data.type,
                    };
                    updateSurveyResponse(questionId, newResponse);
                  }}
                />
              </Label>
            </div>
          );
        case 'locate me':
          return (
            <div key={questionId}>
              <Label Label={data.Label}>
                <div className='w-full'>
                  <ButtonWithIconAndLable
                    iconSrc={{ icon: icons.LOCATE_ME, size: 45, iconColor: '#DEB00F' } as IconProps}
                    label={t("Locate Me")}
                    onClick={async () => {
                      setLoading(true); // Set loading to true when the button is clicked
                      try {
                        const { latitude, longitude } = await GetCurrentLocation();
                        if (latitude && longitude) {
                          setLoading(false);
                          setLocationFetched(true);
                          setTimeout(() => {
                            setLocationFetched(false);
                          }, 1000);
                          const newResponse: LocalSurveyResponse = {
                            questionId,
                            question: '',
                            response: [`${latitude}, ${longitude}`],
                            type: data.type,
                          };
                          updateSurveyResponse(questionId, newResponse);
                        } else {
                          setLoading(false);
                        }
                      } catch (error) {
                        setLoading(false);
                        setPopup(true);
                        setEnableGeolocation(true);
                        console.error('Error processing:', error);
                      }
                    }}
                  />
                  {loading ? (
                    <p className='font-bold text-lg text-center text-black'>Fetching location...</p>
                  ) : (
                    locationFetched && (
                      <p className='font-bold text-lg text-center text-green-600'>Location fetched successfully</p>
                    )
                  )}
                </div>
              </Label>
            </div>
          ); default:
          return null;
      }
    });
    return updatedSteps
  };

  const steps = useMemo(() => {
    return setSteps(surveyJson);
  }, [surveyJson]);

  const handleNextClick = async () => {
    if (!newOutlet) {
      navigate('/home');
    } else {
      const currentSurveyItem = surveyJson[currentStep];
      const questionId = `${currentSurveyItem.type}_${currentStep}`;
      const currentResponse = surveyResponses.find(r => r.questionId === questionId);

      let isValid = true;
      let errorMessage = '';

      switch (currentSurveyItem.type) {
        case 'text':
          if (!currentResponse?.response[0]?.trim()) {
            isValid = false;
            errorMessage = 'The field should not be empty.';
          }
          break;
        case 'checkbox':
          if (!currentResponse?.response.length) {
            isValid = false;
            errorMessage = 'Please select at least one option.';
          }
          break;
        case 'counter':
          if (!currentResponse?.response[0] || parseInt(currentResponse.response[0]) <= 0) {
            isValid = false;
            errorMessage = 'Count should be greater than zero';
          }
          break;
        case 'upload':
          if (!capturedImages.length) {
            isValid = false;
            errorMessage = 'Please capture/upload a picture.';
          }
          break;
        case 'radio':
          if (!currentResponse?.response.length) {
            isValid = false;
            errorMessage = 'Please select an option.';
          }
          break;
        case 'signature':
          if (!currentResponse?.response.length) {
            isValid = false;
            errorMessage = 'Please provide a signature.';
          }
          break;
        case 'date':
          if (!currentResponse?.response[0]) {
            isValid = false;
            errorMessage = 'Please select a date.';
          }
          break;
        case 'locate me':
          if (!currentResponse?.response[0]) {
            isValid = false;
            errorMessage = 'Please locate your position.';
          }
          break;
      }

      if (!isValid) {
        setValidationErrors(prevErrors => [
          ...prevErrors.filter(e => e.key !== questionId),
          { key: questionId, errorMessage, type: currentSurveyItem.type }
        ]);
        return;
      }

      setValidationErrors(prevErrors => prevErrors.filter(e => e.key !== questionId));

      if (currentStep < setSteps(surveyJson).length - 1) {
        setCurrentStep(currentStep + 1);
        dispatch(clearImage())
        setCapturePicture('');
      } else {
        const submissionResponses: GeneratedSurveyResponse[] = surveyResponses.map(({ question, response, type }) => ({
          question,
          response,
          type
        }));

        const requestData: NewOutletSurveyResponseCreateRequest = {
          surveyId: newOutlet?.id,
          surveyData: submissionResponses,
          employeeEmail: employeeDetails?.Email,
          timeStamp: getCurrentTimeStampOfEndMarket(),
          noOfQuestions: memoizedSurveyJson.length,
          noOfAnswered: surveyResponses.length,
        };
        isOnline ? dispatch(createNewOutlet(requestData)) : dispatch(setNewOutLetSurvey(requestData))
        dispatch(clearImage());
        setCapturePicture('');
        dispatch(addRoute(RouterName.SucessfullPage));
        navigate(RouterName.SucessfullPage);
      }
    }
  };

  const handlePreviousClick = () => {
    if (currentStep > 0) {
      const currentQuestionId = `${surveyJson[currentStep].type}_${currentStep}`;
      setValidationErrors(prevErrors => prevErrors.filter(e => e.key !== currentQuestionId));
      setCurrentStep(currentStep - 1);
    }
  };
  console.log('surveyJson', surveyJson)

  return (
    <div className="relative h-screen">
      {!showPopup && <NavigateHeader />}
      {showPopup ? (
        <CameraPopup onCapture={handleCapture} onClose={closePopup} />
      ) : (
        <>
          <Body>
            {!newOutlet ? (
              <div className="flex flex-col items-center justify-center h-full">
                <Icons.WARNING size={100} />
                <h1 className="text-2xl font-bold text-heading items-center mx-5">No survey data available.!</h1>
              </div>
            ) : (
              <>
                <div>{steps[currentStep]}</div>
                {validationErrors.length > 0 && (
                  <div className="validation-errors">
                    {validationErrors.map((error, index) => (
                      <span key={index} className={`${GetStatusColor('pending')}`}>
                        {error.errorMessage}
                      </span>
                    ))}
                  </div>
                )}
              </>
            )}
          </Body>
          <div className="absolute bottom-4 right-4">
            <div className="flex justify-between items-center gap-3">
              {newOutlet && currentStep > 0 && (
                <ButtonWithIcon
                  alt="Previous"
                  color={currentStep === 0 ? 'bg-grey' : 'bg-Ash'}
                  height_and_width="h-20 w-20"
                  icon={icons.LEFT_ARROW}
                  size={36}
                  onClick={handlePreviousClick}
                />
              )}
              <ButtonWithIcon
                alt="Next"
                color="bg-Ash"
                height_and_width="h-20 w-20"
                icon={icons.RIGHT_ARROW}
                size={36}
                onClick={handleNextClick}
              />
            </div>
          </div>
        </>
      )}
      {enableGeolocation && (
        <WarningPopUp
          message={"Enable Geolocation"}
          showPopup={popup}
          onClose={() => {
            setPopup(false)
            setEnableGeolocation(false)
          }}
        />
      )}
    </div>
  );
};

export default Survey;

when trying to capture an image the handleCapture function is throwing an error

import React, {  useRef, useState } from 'react';
import { FiCamera, FiRefreshCw } from 'react-icons/fi';
import { AiOutlineFullscreenExit } from 'react-icons/ai';
import Webcam from 'react-webcam';

interface CameraPopupProps {
    onClose: () => void;
    onCapture?: (imageBase62: string) => void;
}
const CameraPopup: React.FC<CameraPopupProps> = ({ onClose , onCapture }) => {
    const webcamRef = useRef<Webcam | null>(null);
    const [facingMode, setFacingMode] = useState('environment');

    const capture = () => {
        if (webcamRef.current) {
            const newImageSrc = webcamRef.current.getScreenshot();
            if (newImageSrc) {
                onCapture && onCapture(newImageSrc); // Pass newImageSrc to onCapture callback
                onClose();
            } else {
                console.error("Failed to capture image."); // Log error if image capture fails
            }
        } else {
            console.error("Webcam reference is not available."); // Log error if webcam reference is not available
        }
    };
    
    const switchCamera = () => {
        setFacingMode(prevMode => (prevMode === 'user' ? 'environment' : 'user'));
    };

    const isMirrored = facingMode === 'user';

    return (
        <div className="z-index popup z-50">
            <div className="popup-inner">   
                <div className="w-[dvw] h-[dvh] bg-Ash relative">
                    <Webcam
                        mirrored={isMirrored}
                        audio={false}
                        ref={webcamRef}
                        screenshotFormat="image/jpeg"
                        videoConstraints={{ facingMode }}
                        style={{ width: '100dvh', height: '100dvh', objectFit: 'contain' }}
                    />
                    <div className="flex justify-around">
                        <button onClick={capture} className="absolute bottom-4 right-auto bg-white p-2 rounded-full">
                            <FiCamera size={24} color="#000" />
                        </button>
                        <button onClick={switchCamera} className="absolute bottom-4 left-4 bg-white p-2 rounded-full">
                            <FiRefreshCw size={24} color="#000" />
                        </button>
                        <button onClick={onClose} className="absolute bottom-4 right-4 bg-white p-2 rounded-full">
                            <AiOutlineFullscreenExit  size={24} color="#000" />
                        </button>
                    </div>
                </div>
            </div>
        </div>
    );
};

export default CameraPopup;

how can i fix this issue

i have tried to use callback, but becouse the imgSrc on handleCapture is comming from capture function in CameraPopup its throwing an error
<CameraPopup onCapture={()=>handleCapture()} onClose={closePopup} />