如何在 React 中将继承转化为组合(示例)?
How to transform inheritance into composition in React (example)?
我有两种形式:<Login />
和 <Register />
。两者都有 username
和 password
,注册表单也有一个 name
字段。还有一个 login
按钮和一个 register
按钮。他们共享的通用代码只是 username
和 password
所以我想重构我的代码以拥有一个组件 <UsernamePassord />
并在 <Login />
和 [=12] 中使用它=].
到目前为止我做了什么(伪代码):
class UsernamePassword extends React {
constructor() {
this.state = {username: "", password: ""}
}
render() {
return <div>
<input username onChange => setState(username: e.value)
<input password onChange => setState(password: e.value)
</div>
}
class Login extends UsernamePassword {
render() {
return <>
{ super.render() }
<button onClick => this.state.username && this.state.password && signIn() />
}
class Register extends UsernamePassword {
constructor() {
this.state = {
...this.state,
name: ""
}
}
render() {
return <>
<input name onChange => setState(name: e.value)
{ super.render() }
<button onClick => this.state.username && this.state.password && this.state.name && signUp() />
}
我一点也不喜欢这段代码。规模化似乎真的很难。如何使用组合更清洁地完成此操作?
有多种方法可以解决这个问题。您可以创建一个接受道具(在本例中为用户名和密码)并处理值操作的组件。随后它会触发某种 onChange
事件,通知父级更改,父级可以管理状态。或者,您可以管理组件中的状态,只创建一个事件处理程序 prop 来提醒状态的父组件。我根据您的代码制作了第二种情况的 working example(为简单起见,将基于 class 的组件更改为功能组件):
import React, { useState } from "react";
import "./styles.css";
const UsernamePassword = ({ onChange }) => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const handleChange = () => onChange({ username, password });
return (
<div>
<input value={username} onChange={(e) => setUsername(e.target.value)} />
<input value={password} onChange={(e) => setPassword(e.target.value)} />
<button onClick={handleChange}>Click me!</button>
</div>
);
};
const Login = () => {
const onChange = (value) => console.log("Login", value);
return (
<>
<h2>Login</h2>
<UsernamePassword onChange={onChange} />
</>
);
};
const Register = () => {
const onChange = (value) => console.log("Register", value);
return (
<>
<h2>Register</h2>
<UsernamePassword onChange={onChange} />
</>
);
};
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Register />
<Login />
</div>
);
}
我有两种形式:<Login />
和 <Register />
。两者都有 username
和 password
,注册表单也有一个 name
字段。还有一个 login
按钮和一个 register
按钮。他们共享的通用代码只是 username
和 password
所以我想重构我的代码以拥有一个组件 <UsernamePassord />
并在 <Login />
和 [=12] 中使用它=].
到目前为止我做了什么(伪代码):
class UsernamePassword extends React {
constructor() {
this.state = {username: "", password: ""}
}
render() {
return <div>
<input username onChange => setState(username: e.value)
<input password onChange => setState(password: e.value)
</div>
}
class Login extends UsernamePassword {
render() {
return <>
{ super.render() }
<button onClick => this.state.username && this.state.password && signIn() />
}
class Register extends UsernamePassword {
constructor() {
this.state = {
...this.state,
name: ""
}
}
render() {
return <>
<input name onChange => setState(name: e.value)
{ super.render() }
<button onClick => this.state.username && this.state.password && this.state.name && signUp() />
}
我一点也不喜欢这段代码。规模化似乎真的很难。如何使用组合更清洁地完成此操作?
有多种方法可以解决这个问题。您可以创建一个接受道具(在本例中为用户名和密码)并处理值操作的组件。随后它会触发某种 onChange
事件,通知父级更改,父级可以管理状态。或者,您可以管理组件中的状态,只创建一个事件处理程序 prop 来提醒状态的父组件。我根据您的代码制作了第二种情况的 working example(为简单起见,将基于 class 的组件更改为功能组件):
import React, { useState } from "react";
import "./styles.css";
const UsernamePassword = ({ onChange }) => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const handleChange = () => onChange({ username, password });
return (
<div>
<input value={username} onChange={(e) => setUsername(e.target.value)} />
<input value={password} onChange={(e) => setPassword(e.target.value)} />
<button onClick={handleChange}>Click me!</button>
</div>
);
};
const Login = () => {
const onChange = (value) => console.log("Login", value);
return (
<>
<h2>Login</h2>
<UsernamePassword onChange={onChange} />
</>
);
};
const Register = () => {
const onChange = (value) => console.log("Register", value);
return (
<>
<h2>Register</h2>
<UsernamePassword onChange={onChange} />
</>
);
};
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Register />
<Login />
</div>
);
}