我一直遇到无法浏览组件的问题,我总是遇到
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
YES,我知道React的钩子规则,我知道它是如何工作的,但不幸的是这并不能解决我的问题。
我的问题是我有一个和一个EventHandler到
handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {}
,因为我有一个<form>
,这违反了React的钩子规则,但我仍然只能在这个事件中决定是否可以将其定向到仪表板或到错误页面。
我的问题是:有没有办法让这成为可能或完全不同的解决方案?
//the imports of the Login component
import React from "react";
import { Button, Card, Checkbox, Label, TextInput } from "flowbite-react";
import { Link, useNavigate } from "react-router-dom";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faEye, faEyeSlash } from "@fortawesome/free-regular-svg-icons";
import { faArrowLeft, faArrowRightToBracket } from "@fortawesome/free-solid-svg-icons";
//the properties of the Login component
interface LoginProps { }
//the state of the Login component
interface LoginState {
username: string;
password: string;
remember: boolean;
}
//the Login component
export default class Login extends React.Component<LoginProps, LoginState> {
constructor(props: LoginProps) {
super(props);
}
//init the state of the component with empty/default values
state = {
username: "",
password: "",
remember: false,
}
//called after the component was rendered
componentDidMount() {
document.body.style.backgroundImage = 'url("/backgroundDesk.jpg")';
document.body.style.backgroundSize = "cover";
document.body.style.backgroundAttachment = "fixed";
}
//called after the component was unrendered
componentWillUnmount() { }
//called after the component was updated
handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const target: EventTarget & HTMLInputElement = event.target;
const value: string | boolean = target.type === "checkbox" ? target.checked : target.value;
const name: string = target.name;
this.setState({
...this.state,
[name]: value
});
}
//handle the login
handleLogin = (event: React.FormEvent<HTMLFormElement>) => {
//deactivate the default form submit behavior (like reloading the page, put the data in the url, etc.)
event.preventDefault();
console.log(this.state);
//logic can be added here to check the login credentials
const navigate = useNavigate();
navigate("/dashboard");
}
//toggel the password visibility
handelToggelPassword = () => {
//get the password input field
const passwordInput: HTMLElement | null = document.querySelector('input[name="password"]');
const icon_passwordEyeVis: HTMLElement | null = document.getElementById("icon_passwordEyeVis");
const icon_passwordEyeInvis: HTMLElement | null = document.getElementById("icon_passwordEyeInvis");
if (!passwordInput) {
console.error("Password input field not found in the DOM for toggeling the password visibility");
return
}
if (!icon_passwordEyeVis || !icon_passwordEyeInvis) {
console.error("Password eye icon not found in the DOM for toggeling the password visibility");
return
}
if (passwordInput.getAttribute("type") === "password") {
passwordInput.setAttribute("type", "text");
icon_passwordEyeVis.style.display = "none";
icon_passwordEyeInvis.style.display = "block";
} else {
passwordInput.setAttribute("type", "password");
icon_passwordEyeVis.style.display = "block";
icon_passwordEyeInvis.style.display = "none";
}
}
//render the component
render() {
return (
<>
<div className="flex">
<img src="/invoices-manager-logo.png" className="size-28 m-6" />
<label className="text-white font-bold text-5xl flex items-center justify-center">Invoices Manager</label>
</div>
<div className="centerDiv">
<h1 className="text-5xl text-center font-semibold mb-5 text-white">Login</h1>
<Card className="min-w-max bg-opacity-65">
<form className="flex flex-col gap-4" onSubmit={this.handleLogin}>
<div>
<div className="mb-2 block">
<Label className="text-xl" value="E-mail:" />
</div>
<TextInput name="username" type="email" className="text-xl" placeholder="[email protected]" value={this.state.username} onChange={this.handleInputChange} required autoFocus />
</div>
<div>
<div className="mb-2 block">
<Label className="text-xl" value="Password:" />
</div>
<div className="flex">
<TextInput name="password" type="password" className="flex-grow mr-2" placeholder="******" value={this.state.password} onChange={this.handleInputChange} required />
<Button onClick={this.handelToggelPassword} className="w-1/12 pr-5 pl-5">
<FontAwesomeIcon id="icon_passwordEyeVis" icon={faEye} size="xl" />
<FontAwesomeIcon id="icon_passwordEyeInvis" className="hidden" icon={faEyeSlash} size="xl" />
</Button>
</div>
</div>
<div className="flex items-center gap-2 mb-2">
<Checkbox name="remember" onChange={this.handleInputChange} />
<Label className="text-base">Remember me</Label>
</div>
<Button type="submit" className="text-2xl">
<FontAwesomeIcon icon={faArrowRightToBracket} size="xl" className="mr-2" />
Sign in</Button>
<Link to="/register" className="text-blue-600 font-medium">
<FontAwesomeIcon icon={faArrowLeft} size="xl" className="mr-3" />
Sign up</Link>
</form>
</Card>
</div>
</>
);
}
}
您必须考虑不在基于类的组件中使用钩子。
尝试使用旧式高阶组件
withRouter
:
import React from 'react';
import { withRouter } from 'react-router-dom';
class Login extends React.Component {
handleLogin = () => {
// login logic
this.props.history.push('/dashboard');
};
render() {
return (
<div>
<button onClick={this.handleLogin}>Login</button>
</div>
);
}
}
export default withRouter(Login);