reactjs useReducer状态更改在onChange处延迟一个字符

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

当我尝试使用useReducer作为状态管理时,当我使用onChange和reducer时出现了一个问题,这是一个字符延迟。有一个useEffect依赖于字符的变化来将有效性值设置为true或false。
但是它和onBlur配合得很好。
延误的原因是什么?
我该如何解决这个问题?

import React, { useState, useEffect, useReducer, useContext } from "react";
import AuthContext from "../store/auth-context";
import Button from "../UI/Button";
import Card from "../UI/Card";
import Input from "../UI/Input";

const reducerFn = (state, action) => {
  if (action.type === "Email") {
    return {
      ...state,
      emailState: action.value,
    };
  } else if (action.type === "Email_IsValid") {
    return {
      ...state,
      isEmailValid: true,
    };
  } else if (action.type === "Email_IsInValid") {
    return {
      ...state,
      isEmailValid: false,
    };
  } else if (action.type === "Password") {
    return {
      ...state,
      passwordState: action.value,
    };
  } else if (action.type === "Password_IsValid") {
    return {
      ...state,
      isPasswordIsValid: true,
    };
  } else if (action.type === "Password_IsInValid") {
    return {
      ...state,
      isPasswordIsValid: false,
    };
  }
  return { emailState: "", isEmailValid: false, passwordState: "", isPasswordIsValid: false };
};

const Login = () => {
  const [formState, dispatchFn] = useReducer(reducerFn, { emailState: "", isEmailValid: false, passwordState: "", isPasswordIsValid: false });
  const { emailState, isEmailValid, passwordState, isPasswordIsValid } = formState;
  const [isEmailValidated, setIsEmailValidated] = useState(null);
  const [isPasswordIsValidated, setIsPasswordIsValidated] = useState(null);
  const authCtx = useContext(AuthContext);
  useEffect(() => {
    if (isEmailValid) setIsEmailValidated(true);
    if (isPasswordIsValid) setIsPasswordIsValidated(true);
  }, [isEmailValid, isPasswordIsValid]);

  const onEmailChangeHandler = ({ target }) => {
    console.log(isEmailValid, isEmailValidated);
    dispatchFn({ type: "Email", value: target.value });
    if (emailState.includes("@")) {
      dispatchFn({ type: "Email_IsValid" });
    } else {
      dispatchFn({ type: "Email_IsInValid" });
      setIsEmailValidated(false);
    }
  };
  const onEmailBlurHandler = () => {
    if (emailState.includes("@")) {
      dispatchFn({ type: "Email_IsValid" });
    } else {
      dispatchFn({ type: "Email_IsInValid" });
      setIsEmailValidated(false);
    }
  };
  const onPasswordChangeHandler = ({ target }) => {
    dispatchFn({ type: "Password", value: target.value });
    if (passwordState.length > 7) {
      dispatchFn({ type: "Password_IsValid" });
    } else {
      dispatchFn({ type: "Password_IsInValid" });
      setIsPasswordIsValidated(false);
    }
    console.log(isPasswordIsValid);
  };
  const onPasswordBlurHandler = () => {
    if (passwordState.length > 7) {
      dispatchFn({ type: "Password_IsValid" });
    } else {
      dispatchFn({ type: "Password_IsInValid" });
      setIsPasswordIsValidated(false);
    }
  };
  const onFormSubmit = (e) => {
    e.preventDefault();
    if (isEmailValid === false) setIsEmailValidated(false);
    else if (isPasswordIsValid === false) setIsPasswordIsValidated(false);
    else if (isEmailValid && isPasswordIsValid) authCtx.onLogin(emailState, passwordState);
  };
  return (
    <Card>
      <form>
        <Input
          id="email"
          label="E-Mail"
          type="email"
          onChange={onEmailChangeHandler}
          onBlur={onEmailBlurHandler}
          value={emailState}
          isValidated={isEmailValidated}
          warningText="Please enter a valid email; must contains '@'"
        />
        <Input
          id="password"
          label="Password"
          type="password"
          onChange={onPasswordChangeHandler}
          onBlur={onPasswordBlurHandler}
          value={passwordState}
          isValidated={isPasswordIsValidated}
          warningText="Password must have 8 characters long"
        />
        <Button label="Login" onClick={onFormSubmit} classes={`bgRed bgWider`}></Button>
      </form>
    </Card>
  );
};

export default Login;
rslzwgfq

rslzwgfq1#

在这里,如果不使用归约器,你会有一个简单得多的时间,就像这样:

import React from "react";

const Login = () => {
  const [email, setEmail] = React.useState("");
  const [password, setPassword] = React.useState("");
  const [shouldValidateEmail, setShouldValidateEmail] = React.useState(false);
  const [shouldValidatePassword, setShouldValidatePassword] = React.useState(false);
  const emailIsValid = email.includes("@");
  const passwordIsValid = password.length > 7;
  const errors = [
    shouldValidateEmail && !emailIsValid ? "Email invalid" : null,
    shouldValidatePassword && !passwordIsValid ? "Password invalid" : null,
  ]
    .filter(Boolean)
    .join(", ");

  return (
    <form>
      Email
      <input
        id="email"
        type="email"
        onChange={(e) => setEmail(e.target.value)}
        onBlur={() => setShouldValidateEmail(true)}
        value={email}
      />
      <br />
      Password
      <input
        id="password"
        type="password"
        onChange={(e) => setPassword(e.target.value)}
        onBlur={(e) => setShouldValidatePassword(true)}
        value={password}
      />
      <br />
      {errors ? <>Errors: {errors}</> : null}
    </form>
  );
};

export default function App() {
  const [resetKey, setResetKey] = React.useState(0);
  return (
    <div className="App">
      <Login key={resetKey} />
      <hr />
      <button onClick={() => setResetKey((k) => k + 1)}>Reset</button>
    </div>
  );
}

但是,如果您确实想使用reducer,只需将验证状态与状态更改时的状态相耦合即可:

function validateEmail(email) {
  return email.includes("@");
}

function validatePassword(password) {
  return password.length > 7;
}

const initialState = {
  emailState: "",
  isEmailValid: false,
  passwordState: "",
  isPasswordValid: false,
};

const reducerFn = (state, action) => {
  if (action.type === "Email") {
    return {
      ...state,
      emailState: action.value,
      isEmailValid: validateEmail(action.value),
    };
  } else if (action.type === "Password") {
    return {
      ...state,
      passwordState: action.value,
      isPasswordValid: validatePassword(action.value),
    };
  }
  return initialState;
};

const Login = () => {
  const [{ emailState, isEmailValid, passwordState, isPasswordValid }, dispatchFn] = React.useReducer(
    reducerFn,
    initialState,
  );
  const errors = [
    emailState && !isEmailValid ? "Email invalid" : null,
    passwordState && !isPasswordValid ? "Password invalid" : null,
  ]
    .filter(Boolean)
    .join(", ");

  return (
    <form>
      Email
      <input
        id="email"
        type="email"
        onChange={(e) => dispatchFn({ type: "Email", value: e.target.value })}
        value={emailState}
      />
      <br />
      Password
      <input
        id="password"
        type="password"
        onChange={(e) => dispatchFn({ type: "Password", value: e.target.value })}
        value={passwordState}
      />
      <br />
      {errors ? <>Errors: {errors}</> : null}
    </form>
  );
};

相关问题