我对React中的继承和组合有疑问。
我习惯了Backbone,其中通常的过程是创建处理数据和渲染逻辑的类视图。当您有一些共享某些逻辑的组件(例如表单)时,可以对其进行抽象创建一个新组件(一个类),在其中添加共享的逻辑,然后从其他组件扩展该类。这样,最终将得到具有共享逻辑和扩展它的组件的抽象组件:
var generalForm = Backbone.View.extend({
customMethod: function (){
// Some shared logic
}
});
var Form = generalForm.extend({
// This class has customMethod from generalForm.
});
现在我看到React使用的是合成而不是继承。进行组合的方法有两种:包装组件或使用Higher-Order Components。为了使事情变得更容易,我对这两种可能性进行了沙盒测试:https://codesandbox.io/s/wyn629rm4l。
进行合成的第一种方法是将一个组件包装在另一个组件中:
class Form extends Component {
constructor(props) {
super(props);
this.state = {};
}
handleUpdate(e) {
this.setState({
[e.target.name]: e.target.value
});
}
render() {
return (
<div className="Form">
<input
type="text"
name="name"
onChange={e => {
this.handleUpdate(e);
}}
/>
</div>
);
}
}
class GeneralForm extends Component {
constructor(props) {
super(props);
}
render() {
return <form className="GeneralForm">{this.props.children}</form>;
}
}
class App extends Component {
render() {
return (
<GeneralForm>
<Form />
</GeneralForm>
);
}
}
第一个问题:是否有一种优雅而有效的方法将逻辑从子组件(Form
)发送到包装器组件(GeneralForm
),例如handleUpdate
函数?
组成作品的另一种方法是使用高阶组件。我们创建一个函数,该函数返回具有某些逻辑的组件。然后,我们将一个组件传递给此函数,结果将是具有该函数设置的逻辑的组件。这样,我们可以创建共享逻辑的组件。
const CustomFormHoc = WrappedComponent => {
return class CustomForm extends Component {
constructor(props) {
super(props);
this.state = {};
this.handleUpdate = this.handleUpdate.bind(this);
this.submitForm = this.submitForm.bind(this);
}
submitForm(e) {
e.preventDefault();
alert(JSON.stringify(this.state, null, 2));
}
handleUpdate(e) {
this.setState({
[e.target.name]: e.target.value
});
}
render() {
return (
<WrappedComponent
{...this.props}
handleUpdate={this.handleUpdate}
submitForm={this.submitForm}
/>
);
}
};
};
class Form extends Component {
render() {
return (
<div className="Form">
<div>Form</div>
<div className="Form">
<input
type="text"
name="Address"
placeholder="Address"
onChange={e => {
this.props.handleUpdate(e);
}}
/>
<input
type="text"
name="Postal code"
placeholder="Postal code"
onChange={e => {
this.props.handleUpdate(e);
}}
/>
<input
type="submit"
onClick={e => {
this.props.submitForm(e);
}}
/>
</div>
</div>
);
}
}
let ComposedForm = CustomFormHoc(Form);
class App extends Component {
render() {
return (
<div>
<ComposedForm />
</div>
);
}
}
这可行,但是这是我的第二个问题:是否有一种方法可以避免将handleUpdate和SubmitForm传递给WrappedComponent
?在Higher-Order Components示例中,它们被忽略了。
<WrappedComponent
{...this.props}
handleUpdate={this.handleUpdate}
submitForm={this.submitForm}
/>
最后一个问题:这两种制作构图的方式中哪种更好,在哪种情况下?
谢谢!