Как вызвать родительский метод из React Child с помощью Super call? - PullRequest
0 голосов
/ 01 мая 2020

Я хочу иметь возможность абстрагироваться от того, как работает логика компонентов React c, отделяющая логики представления c от обработчиков

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>

Рабочий StackBlitzLink

Я ошибаюсь при таком подходе? Если Нет, почему это не работает для clickHandler, то, что я смотрю, это расширение компонента, чтобы иметь logi c, и функции рендеринга, как отдельные, все нажатия кнопки и методы будут выполняться в родительском элементе, чтобы мы могли разделить логи c, а затем может быть общим кодом для React и RN, но это вторично.

Лучше всего, чтобы clickHandler был прикреплен к какому-либо свойству-прототипу родительского класса, так как это метод с привязкой, и щелчок работает как это нормальный метод, не связанный с компонентом, но можем ли мы обойти это и можем ли мы решить эту проблему? И огонь методом только по нажатию

Ответы [ 3 ]

0 голосов
/ 01 мая 2020

Ваш подход - тот, который не рекомендуется и, возможно, даже анти-шаблон для реагирования на композиционную модель реакции. Обратитесь к разделу Состав против наследования в документации, чтобы узнать, почему состав лучше, чем наследование в реакции, и как решить некоторые проблемы с составом, когда разработчики достигают наследования. В вашем случае вам следует взглянуть на Специализация

Вы должны почти всегда расширить компоненты React с React.Component.

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>

Вот разветвленная рабочая версия вашего стекаблита. Рабочий стекBlitzLink

0 голосов
/ 04 мая 2020

Как упоминал @ hassaan-tauqir, обычно предпочитают использовать композицию, а не наследование. Но если вы действительно хотите это сделать, вы можете использовать следующий код

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>

Надеюсь, это поможет вам

0 голосов
/ 01 мая 2020

Да, поскольку вы заявили, что ваш подход неверен, в React вы хотите разделить использование кода по составу компонентов вместо наследования.

Я собираюсь использовать нечто похожее на ваш пример, чтобы помочь вам понять концепцию, скажем, вы хотите создать базовый компонент с именем IconButton, который будет кнопкой с текстом рядом со значком, и вы хотите использовать повторно этот компонент для создания еще двух компонентов DangerIconButton (это кнопка со значком, который должен представлять опасную ситуацию, например операцию удаления), и вы хотите создать SuccessfulIconButton (кнопку, где вы хотите представить желаемое действие)

Теперь, основываясь на наших требованиях, мы видим, что функциональность всех трех компонентов одинакова, в основном это обработчик кликов, но отличается визуальное представление (значок и стили, примененные к кнопке).

давайте создадим наш базовый компонент

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} />

   }
}

конечно, здесь вы хотите лучше назвать и вы все еще хотите сделать общий стиль для всех ваши иконки, такие как padding, и другие вещи. но, надеюсь, концепция прошла через

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...