繁体   English   中英

如何使用 Super 调用从 React Child 调用父方法?

[英]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}>&#9650;</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>

工作堆栈BlitzLink

我对这种方法有错吗? 如果没有,为什么这不适用于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}>&#9650;</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}>&#9650;</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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM