如何在 React 中将继承转化为组合(示例)?

How to transform inheritance into composition in React (example)?

我有两种形式:<Login /><Register />。两者都有 usernamepassword,注册表单也有一个 name 字段。还有一个 login 按钮和一个 register 按钮。他们共享的通用代码只是 usernamepassword 所以我想重构我的代码以拥有一个组件 <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>
  );
}