[英]How to call parent method from React Child using Super call?
我希望能够抽象出 React 组件逻辑的工作方式,将视图逻辑与处理程序分开
class SuccessLabelWithIcon extends Label{ constructor(props){ super(props); this.className = this.className + ' success-label'; } render(){ return <div> <div onClick={super.onClick}>▲</div> // this works but fires initially too in StackBlitz but not in SO not sure why, but changing to clickHandler dosent work. </div> } } class Label extends React.Component{ constructor(props){ super(props); this.className='plain-label'; } clickHandler = () => { console.log('Inherited'); } onClick() { console.log('Inherited'); } render(){ return <span className={this.className}> {this.props.children} </span> } } // Render it ReactDOM.render( <SuccessLabelWithIcon/>, document.getElementById("react") );
<div id="react"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
我对这种方法有错吗? 如果没有,为什么这不适用于clickHandler,我正在查看的是扩展组件以具有逻辑和渲染功能,所有按钮点击和方法都将在父级中执行,以便我们可以分离逻辑,然后也许在 React 和 RN 之间共享代码,但那是次要的?
我最好的选择是 clickHandler 附加到父 class 的一些原型属性,因为它是一种绑定方法,并且 click 是一种未绑定到组件的正常方法,但我们可以绕过这个,我们可以缓解这个问题吗? 并且仅在点击时触发方法
是的,正如您所说的那样,您的方法不正确,在 React 中,您希望通过组件组合而不是 inheritance 来共享代码使用情况。
我将使用与您的示例类似的东西来帮助您理解这个概念,假设您要创建一个名为 IconButton 的基本组件,该组件将是一个带有图标旁边的文本按钮,并且您想重用该组件来再创建两个组件 DangerIconButton(这是一个带有图标的按钮,用于表示像删除操作这样的危险情况),并且您想要创建一个 SuccessIconButton(您想要表示所需操作的按钮)
现在根据我们的要求,我们看到所有三个组件的功能是相同的,基本上是一个单击处理程序,但不同的是视觉表示(图标和 styles 应用于按钮)。
让我们创建我们的基础组件
class IconButton extends React.Component{
render(){
return <button onClick={props.onClick} style={props.style}>
<img src={props.icon} />
<span>button text</span>
</button>
}
}
现在我们的另外两个组件将更简单,并将使用该基础组件
class SuccessfulIconButton extends React.Component{
render(){
// notice how i'm creating this component by composition of other components
// happyIcon and green are what makes this a successful butoon
return <IconButton onClick={props.onClick} style={{background: 'green'}} icon={happyIcon} />
}
}
class DangerIconButton extends React.Component{
render(){
// notice that i'm getting the onClick handler here through props, because u want the parent components of this component to have their specific handlers
return <IconButton onClick={props.onClick} style={{background: 'red'}} icon={dangerIcon} />
}
}
当然,在这里你想要更好的命名,你仍然想为你的所有 IconButtons 做一些共同的样式,比如填充和其他东西。 但希望这个概念能够通过
您的方法是一种不推荐的方法,甚至可能是一种反模式来反应成分 model。 请参阅文档中的合成与 Inheritance部分,了解为什么合成在反应中优于 inheritance 以及如何处理开发人员使用 inheritance 的合成问题。 在您的情况下,您应该查看专业化
你应该几乎总是从React.Component
扩展 React 组件。
class SuccessLabelWithIcon extends Label{ constructor(props){ super(props); } render() { return ( // Specialization <Label>Success</Label> ) } } class Label extends React.Component{ constructor(props){ super(props); } clickHandler = () => { console.log('Inherited'); } onClick() { console.log('Inherited'); } render(){ return <span className="plain-label" onClick={this.onClick}> {this.props.children} </span> } }
<div id="react"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
这是你的 stackblitz 的一个分叉的工作版本。 工作堆栈BlitzLink
正如@hassaan-tauqir 所提到的,它通常更喜欢使用组合而不是 inheritance。 但是如果你真的想这样做,你可以使用下面的代码
class Label extends React.Component{ constructor(props){ super(props); this.className='plain-label'; } clickHandler = () => { console.log('Inherited'); } onClick() { console.log('Inherited'); } render(){ return <span className={this.className}> {this.props.children} </span> } } class SuccessLabelWithIcon extends Label{ constructor(props){ super(props); this.className = this.className + ' success-label'; } render(){ return (<Label><div> <div onClick={this.clickHandler}>▲</div> // this works but fires initially too in StackBlitz but not in SO not sure why, but changing to clickHandler dosent work. </div></Label>); } } // Render it ReactDOM.render( <SuccessLabelWithIcon/>, document.getElementById("react") );
<div id="react"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
clickHandler
不起作用的原因是因为您使用arrow functions
来定义它(基本上它没有您的 SuccessLabelWithIcon 上下文,而是具有Label
的上下文)。
您可以使它成为一个简单的方法,或者您可以简单地使用this
而不是super
(因为您正在扩展组件)。
class Label extends React.Component{ constructor(props){ super(props); this.className='plain-label'; } clickHandler = () =>{ console.log('Inherited'); } onClick() { console.log('Inherited'); } render(){ return <span className={this.className}> {this.props.children} </span> } } class SuccessLabelWithIcon extends Label{ constructor(props){ super(props); this.className = this.className + ' success-label'; } render(){ return (<Label><div> <div onClick={this.clickHandler}>▲</div> // this works but fires initially too in StackBlitz but not in SO not sure why, but changing to clickHandler dosent work. </div></Label>); } } // Render it ReactDOM.render( <SuccessLabelWithIcon/>, document.getElementById("react") );
<div id="react"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
希望这可以帮助你
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.