Han*_*ans 5 inheritance composition reactjs
我很难在 React 中用继承代替组合。我将尝试基于 React 风格指南中不鼓励的继承来解释所提出的问题和我当前的解决方案。
首先,我在超级组件中定义公共状态和方法:
export default class SuperComponent extends Component {
constructor(props) {
super(props);
this.state = commonState;
}
foo() {
this.setState({a: 3});
}
render() {
return (
<div>
{this.getContent()}
</div>
)
}
}
Run Code Online (Sandbox Code Playgroud)
然后我制作具有更多状态和方法的子组件。这些也应该可以访问超级组件的状态:
export default class SubComponent1 extends SuperComponent {
constructor(props) {
super(props);
this.state = Object.assign(this.state, subComponent1State);
}
bar() {
this.setState({b: 7});
}
getContent() {
return (
<div>
I'm subcomponent 1
</div>
)
}
}
export default class SubComponent2 extends SuperComponent {
constructor(props) {
super(props);
this.state = Object.assign(this.state, subComponent2State);
}
bar() {
this.setState({c: 1});
}
getContent() {
return (
<div>
I'm subcomponent 2
</div>
)
}
}
Run Code Online (Sandbox Code Playgroud)
当我尝试将其转换为基于组合的方法时,我得到以下结果:
export default class SuperComponent extends Component {
foo() {
this.props.setStateMethod({a: 3});
}
render() {
return (
<div>
<div>
{this.props.text}
</div>
</div>
)
}
}
export default class SubComponent1 extends Component {
constructor(props) {
super(props);
this.state = Object.assign(commonState, subComponent1State);
}
bar() {
this.setState({b: 7});
}
render() {
return (
<SuperComponent
text={"I'm subcomponent 1"}
setStateMethod={this.setState}
subComponentState={this.state}
/>
)
}
}
export default class SubComponent2 extends Component {
constructor(props) {
super(props);
this.state = Object.assign(commonState, subComponent2State);
}
bar() {
this.setState({c: 1});
}
render() {
return (
<SuperComponent
text={"I'm subcomponent 2"}
setStateMethod={this.setState}
subComponentState={this.state}
/>
)
}
}
Run Code Online (Sandbox Code Playgroud)
这是将基于继承的解决方案转换为基于组合的解决方案的好方法吗?既然公共状态和差异状态更好地分开,基于继承的状态不是更好吗?在基于组合的解决方案中,必须在初始化时定义每个子组件中的公共状态。
首先,您应该阅读React 团队对此事的回应。
代码非常模糊,所以我无法判断你的情况是否真的很特殊,但我对此表示怀疑,所以让我来解决普遍共识:
继承和组合在真空中同样有用。在某些语言或项目中,您会更喜欢继承一个公共类,而不是导入和调用十几个函数,但在 React 中,主要是因为它是以组件为中心的方法,事实恰恰相反。
组合使 React 只关注两件事:props和state。你相信你收到的东西,以可预测的方式行动,并反映props在state你所呈现的东西中。如果您需要稍微更改渲染的内容,您可以发送不同的组件props,甚至可以制作一个组件来包装第一个组件以供特定用途。该组件甚至可以拥有自己的一些逻辑,并通过渲染道具将其传递下来,以便您可以更精确地控制结果。如果您需要使用此逻辑包装不同的组件,您可以制作HOC并轻松包装任何组件。那时,您可以创建数十个组件,将不同的内容返回到相同的内容props,并且可以在组件库之间切换以显示数据并处理数据。
尽管 Render props 或 HOC 之类的东西看起来不同,但它们只是使用现有组件逻辑的技术,并以允许您重用代码并在 React 中仍然有意义的方式应用它。这是一个好的解决方案吗?好吧,它确实有效,但你最终会陷入困境并杂耍二十个几乎相同的概念。这就是为什么现在有人提出了一个介于继承和组合之间的改变范式的新功能的提案。但在 React 的做事方式中,组合仍然没有什么意义。
归根结底,这只是看待同一问题的不同方式。组合与 React 配合得更好,让您可以更好地控制render混合和匹配您所需要的内容。
再说一次,如果你有一个实际的例子,我可以给你一个更好的解释,应用不同的 React 技术,但对于你当前的技术,显然没有好或坏的方法来做到这一点,因为它什么也不做。这需要一些时间修补而不是解释。
在这种情况下,我认为您的解决方案不是最好的基于组合的解决方案。由于您希望子组件有自己的状态(并且我假设它们有自己的逻辑),所以我会使用这样的临时组件:
// hoc.js
const withSuper = (SubComponent) => {
class WithSuper extends React.Component {
constructor(props) {
super(props);
this.foo = this.foo.bind(this);
}
foo() { // could also receive a value
this.props.setState({ a: 3 });
}
render() {
// Passes to the SubComponent:
// the state.a as a prop
// function foo to modify state.a
// the rest of the props that may be passed from above
return (
<SubComponent
a={this.state.a}
foo={this.foo}
{...this.props}
/>
)
}
}
return WithSuper;
};
// SubComponent1.js
class SubComponent1 extends Component {
constructor(props) {
super(props);
this.state = { b: 0 }; // or anything else
}
bar() {
this.setState({b: 7});
}
render() {
// to access the 'a' value use: this.props.a
// to modify the 'a' value call: this.props.foo()
return (
<div>
I'm subcomponent 1
</div>
);
}
}
export default withSuper(SubComponent1);Run Code Online (Sandbox Code Playgroud)
也SubComponent2将被包装:withSuper(SubComponent2),因此它也可以访问a和foo()道具。
我认为这个解决方案更好,因为特设的“Super”封装了 的行为a,而子组件只需要担心修改其特定状态。