0

我有一个不必要地重新渲染的登录组件。我已经用React.memo包装了组件,并且正在使用useCallBack钩子来防止在每次渲染时创建这些函数,如果值没有改变......

考虑以下:

我有一个通用的 FormComponent ,它得到一个道具:

function FormComponent({
   formType
}) { ....}

export default React.memo(FormComponent)

该道具将在我拥有的不同表单之间切换,例如登录、注册等。在我的示例中,我只是显示登录表单,我想我只是将解决方案应用于其他表单。

function FormComponent({
  formType
}) {

/* various setstate removed for brevity */

  const Forms = {
    Login: [LoginForm,
      () => loginSubmit(
        email,
        password,
        setEmail,
        setPassword,
        setFormError,
        setFormSuccess,
        setIsLoading,
        setResponseMessage,
        dispatch,
        router,
        user,
        mutate
      )
    ]
  };

  function handleChangeForUseCallBack(name, value) {
    setResponseMessage('');
    setPasswordFeedback('')
    setPasswordConfirmationFeedback('')
    setFormError(false);
    setFormSuccess(false);
    setEmailError(false);
    setPasswordError(false);
    setPasswordConfirmationError(false);
    setDisableButton(false);

    dispatch({ type: 'resetUserAccountIsVerified', })

    setEmailDup(false);


    if (value === '') setDisableButton(() => true)

    if (name === 'email') {
      setEmail(value);
    }

    if (name === 'password') {
      setPassword(value);
    }

    if (name === 'password_confirmation') {
      setPasswordConfirmation(value);
    }

    if (name === 'current_location') {
      setCurrentLocation(value);
    }

    if (name === 'current_destination') {
      setCurrentDestination(value);
    }

    if (name === 'interested_activities') {
      setInterestedActivitiesInput(value);
    }
  }

  const handleChange = useCallback((e) => {
    e.persist();
    const { name, value } = e.target;
    handleChangeForUseCallBack(name, value);
  }, [email, formType, password, password_confirmation, handleChangeForUseCallBack, setIsLoading]);

  function handleSubmitForUseCallBack(e, form) {
    e.preventDefault();
    setDisableButton(true);
    validateInputs(
      form,
      email,
      setEmailError,
      setEmailFeedback,
      password,
      password_confirmation,
      setPasswordConfirmationError,
      setPasswordConfirmationFeedback,
      setPasswordError,
      setPasswordFeedback,
      setFormSuccess,
      setFormError,
    );
    return preventSubmit ? false : Forms[form][1]()
  }

  const handleSubmit = useCallback((e, form) => {
    handleSubmitForUseCallBack(e, form);
  }, [email, password, password_confirmation, interestedActivities, handleSubmitForUseCallBack]);

  function LoginForm() {
    useEffect(() => {
      dispatch({ type: 'resetUserAccountIsVerified' })
    }, [id]);

    return (
      mounted && <GenericFormComponent
        handleSubmit={handleSubmit}
        formType={formType}
        formSuccess={formSuccess}
        formError={formError}
        accountNotVerified={accountNotVerified}
        email={email}
        emailError={emailError}
        emailFeedback={emailFeedback}
        handleChange={handleChange}
        password={password}
        passwordError={passwordError}
        passwordFeedback={passwordFeedback}
        disableButton={disableButton}
        buttonName="Log-in"
        isLoading={isLoading}
        setIsLoading={setIsLoading}
        responseMessage={responseMessage}
      />
    );
  }

  return Forms[formType][0]();
}

问题是 handleSubmit 有各种函数调用和传递的值需要传递到useCallback依赖项中吗?

任何帮助,将不胜感激!

4

1 回答 1

0

我不认为useCallback是这里的问题。LoginForm一个潜在的原因可能是渲染时运行的以下副作用:

useEffect(() => {
  dispatch({ type: 'resetUserAccountIsVerified' })
}, [id]);

但我可能错了。我认为这里的明确问题是LoginForm在您的FormComponent. 由于它在FormComponent每次定义的内部都FormComponent被重新评估(例如,从状态变化),LoginForm将被重新初始化,因此如果它已经被渲染,那么它将重新渲染。我认为定义LoginForm其他地方会解决你的问题。

于 2022-03-05T23:51:50.213 回答