如何重写将另一个类扩展为无状态功能组件的React类?

时间:2019-12-26 11:03:48

标签: javascript reactjs

我有以下简单的代码,我试图将其重写为避免类的函数,并使用挂钩进行学习。 如下所示,“应用”扩展了“表格”。完整的代码包括“窗体”中的其他功能,例如,验证功能,该功能由“ handleChange”调用并修改状态中的“错误”项。 请注意,“表单”不是“应用程序”的一部分,因为表单将被其他组件(例如登录组件)重用。

我的主要问题:

1-根据documentation,他们似乎不鼓励使用继承,如何在不使用“扩展”(并保留类)的情况下重写继承?

2-如何在不使用类的情况下重写它?

到目前为止,我想到的唯一想法是将form.jsx中的所有函数重写为独立函数,然后从App调用它们(请参见下文)。但这意味着要编写许多道具和参数(特别是当添加验证时为“错误”时,“ setErrors”,“模式”等将从“ App”发送到“ renderInput”,从此处发送到“ handleChange”等 它可以工作,但是代码不像以前那么干净...

app.js

class App extends Form {
  state = {
    data: { username: "", password: "" },
  };

  render() {
    return (
      <form action="">
        {this.renderInput("username", "Username")}
        {this.renderInput("password", "Password", "password")}
      </form>
    );
  }
}

form.jsx

class Form extends Component {
  state = {
    data: {},
  };

  handleChange = ({ currentTarget }) => {
    const data = { ...this.state.data };
    data[currentTarget.name] = currentTarget.value;
    this.setState({ data });
  };

  renderInput(name, label, type = "text") {
    const { data, errors } = this.state;

    return (
      <Input
        name={name}
        type={type}
        value={data[name]}
        label={label}
        onChange={this.handleChange}
      />
    );
  }

  render() {
    return null;
  }
}

export default Form;

input.jsx

const Input = ({ name, label, ...rest }) => {
  return (
    <div className="form-group">
      <label htmlFor={name}>{label}</label>
      <input {...rest} name={name} id={name} className="form-control" />
    </div>
  );
};

尝试将其更改为功能:

App.jsx

const App = () => {
  const [user, setUser] = useState({ username: "", password: "" });

  return (
    <form action="">
      {renderInput("username", "Username", user, setUser)}
      {renderInput("password", "Password", user, setUser, "password")}
    </form>
  );
};

form.jsx

export function handleChange({ currentTarget }, data, setData) {
  setData({ ...data, [currentTarget.name]: currentTarget.value });
}

export function renderInput(name, label, data, setData, type = "text") {
  return (
    <Input
      name={name}
      type={type}
      value={data[name]}
      label={label}
      onChange={e => handleChange(e, data, setData)}
    />
  );
}

在此先感谢您是否需要更好的解释或完整的代码。

1 个答案:

答案 0 :(得分:2)

form移至Form组件并传递输入属性的数组以生成输入:

App.jsx

const App = () => {
  const [user, setUser] = useState({ username: "", password: "" });

  const inputList = [
    {name: "username", label: "Username", value: user.username},
    {name: "password", label: "Password", value: user.password, type: "password"}
  ]

  return (
    <Form inputList={inputList} setData={setUser} />
  );
};

Form.jsx

const Form = ({ inputList, setData }) => {

  const handleChange = ({ currentTarget }) => {
    const { name, value } = currentTarget;
    setData(prevData => ({ ...prevData, [name]: value }));
  };

  return (
    <form action="">
      {
        inputList.map(({ name, label, value, type = "text" }) => 
          <Input
            key={name}
            name={name}
            type={type}
            value={value}
            label={label}
            onChange={handleChange}
          />
        )
      }
    </form>     
  );

}