我已经检查了其他问题,他们没有帮助我
我构建了一个React钩子来验证表单输入。但是,这会导致无限的重新渲染循环。我已将问题归结为useEffect
依赖项数组。当我排除validators
依赖项时,它的效果很好!我永远不会在运行时更改validators
,所以在依赖项数组中不需要此道具吗?我的ESLint
react-hooks-plugin
一直警告我validators
依赖项丢失。请帮帮我。如果我在运行时不进行更改,是否可以从validators
依赖项数组中删除useEffect
依赖项?这是我的钩子和表单组件:
import { useState, useEffect } from "react";
function setObjectValues<
K extends { [key: string]: unknown },
T
>(
object: K,
value: T
): { [key in keyof K]?: T } {
const initialResults: {
[key in keyof K]?: T;
} = {};
for (const key in object) {
initialResults[key] = value;
}
return initialResults;
}
export function useValidation<
K,
T extends {
[key: string]: (value: K) => boolean;
}
>(
value: K,
validators: T
): {
valid: boolean;
results: { [key in keyof T]?: boolean };
} {
const [results, setResults] = useState<
{ [key in keyof T]?: boolean }
>(setObjectValues(validators, true));
useEffect(() => {
const newResults: {
[key in keyof T]?: boolean;
} = {};
for (const key in validators) {
const valid = validators[key](value);
newResults[key] = valid;
}
setResults(newResults);
}, [value, validators]);
const valid = Object.values(results).every(
(item) => item === true
);
return { valid, results };
}
我的组件
import { NextPage } from "next";
import {
useFirebase,
useValidation,
} from "app/hooks";
import {
useState,
useCallback,
FormEvent,
} from "react";
import { useRouter } from "next/router";
type InputType = "email" | "password";
const SignUp: NextPage = () => {
const firebase = useFirebase();
const router = useRouter();
const [email, setEmail] = useState("");
const {
valid: emailValid,
results: emailValidationResults,
} = useValidation(email, {
containsAt: (value) => value.includes("@"),
});
const [password, setPassword] = useState("");
const {
valid: passwordValid,
results: passwordValidationResults,
} = useValidation(password, {
isLongEnough: (value) => value.length >= 8,
containsLowerCase: (value) =>
value.toUpperCase() !== value,
containsUpperCase: (value) =>
value.toLowerCase() !== value,
containsNumber: (value) => /\d/.test(value),
});
const handleSubmit = useCallback(
(event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (
emailValid === true &&
passwordValid === true &&
email !== "" &&
password !== ""
) {
const error = firebase.createUser(
email,
password
);
if (error) {
console.warn(error.code);
} else {
router.push("/");
}
} else {
console.warn("Invalid user values");
}
},
[
email,
emailValid,
firebase,
password,
passwordValid,
router,
]
);
console.log(emailValid, passwordValid);
return (
<form onSubmit={handleSubmit}>
<label htmlFor="email">Email</label>
<input
value={email}
onChange={(event): void =>
setEmail(event.target.value)
}
id="email"
placeholder="Email"
/>
<p>{emailValid}</p>
<label htmlFor="password">Password</label>
<input
value={password}
onChange={(event): void =>
setPassword(event.target.value)
}
id="password"
placeholder="Password"
/>
<p>{passwordValid}</p>
<button type="submit">Submit</button>
</form>
);
};
export default SignUp;
答案 0 :(得分:2)
const {
valid: passwordValid,
results: passwordValidationResults,
} = useValidation(password, {
isLongEnough: (value) => value.length >= 8,
containsLowerCase: (value) =>
value.toUpperCase() !== value,
containsUpperCase: (value) =>
value.toLowerCase() !== value,
containsNumber: (value) => /\d/.test(value),
});
在这里,validators
实际上是在Signup
渲染期间创建的对象。创建新对象时,尽管其中的值可能相同,但它始终是一个不同的新对象。这就是为什么将其添加到依赖关系数组会导致无限重新渲染的原因。
如果对象不依赖于组件的状态或道具,请将声明移到组件外部,以便仅创建一次。
// outside SignUp
const validators = {
isLongEnough: (value) => value.length >= 8,
containsLowerCase: (value) =>
value.toUpperCase() !== value,
containsUpperCase: (value) =>
value.toLowerCase() !== value,
containsNumber: (value) => /\d/.test(value),
};
// inside SignUp
const {
valid: passwordValid,
results: passwordValidationResults,
} = useValidation(password, validators);
我建议将validators
保留在依赖项数组中,因为它仍然可以正常工作。大多数情况下将其遗漏是一种代码异味。在大多数情况下,如果validators
发生了变化,您将希望再次重新运行效果。