Правильный способ наследования компонентов React

Я понимаю, что мой вопрос немного предвзят, но я очень новичок в Javascript и prototypes, и я читал об этом, но я действительно не понимаю, как применять эти методы к моим практическим задачам. Так что пример был бы очень полезен. Итак, у меня есть компонент React, который в основном выглядит так:

var Component1 = React.createClass({

getInitialState: function () {
        return ({
            searchable: true,
        })
    },

function1: function () {
        return ({
            somevalue
        })
    },

render: function () {

        var redText = {
            color: 'red'
        };

        var redBorder = {
            color: 'red',
            border: '1px solid red'

        };

        return (
                <form>
                    <div>
                        <a onClick={this.props.handleAddClick}>Something</a>
                    </div>

                    <div>
                        <label>Some label</label>
                        <input type="text"/>
                    </div>
               </form> ) 
});

У меня также есть Component2, который в принципе абсолютно такой же, но имеет один дополнительный <input/> внутри return его функции render.

У меня также есть Component3, который выполняет те же функции, но имеет другую функцию render().

Так как же применить здесь наследование и не копировать-вставить 3 раза? Мне просто не хватает практической иллюстрации, поэтому я был бы признателен.

Edit1_________________________________________________________________ Итак, я попытался реализовать наследование прототипов в соответствии с первым ответом, но, похоже, React не видит этих функций: getInitialState() равно null, начальное состояние после рендеринга равно null. Что не так с этим подходом?

Я тоже попробовал пойти по учебнику и сделал:

function MyPrototype() {};
MyPrototype.prototype.getInitialState = function () {
    return ({
        someProperty: true;
    })
};

function Component1() {};
Component1.prototype = Object.create(MyPrototype.prototype);
Component1.prototype.render = function () {
    console.log(this);
    return (<div></div>)};

var MyComponent1 = React.createClass(new Component1());

Но когда я открываю браузер, я получаю сообщение об ошибке: Uncaught Invariant Violation: createClass(...): Class specification must implement arendermethod.

Что я делаю неправильно?

Редактировать2_______________________________________________

На самом деле, я вижу, что React не поддерживает миксины и прототипы. Вместо этого следует использовать состав. Это объясняется в этой статье: Dan Статья Абрамова Миксины мертвы. Да здравствует композиция


person Battle_Slug    schedule 02.05.2016    source источник


Ответы (1)


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

Вот пример использования композиции:

class Button extends Component {
  render() {
    return (
      <div className='Button' style={{ color: this.props.color }}>
        {this.props.children}
      </div>
    )
  }
}

class DeleteButton extends Component {
  render() {
    return (
      <Button color='red'>Delete</Button>
    )
  }
}

Обратите внимание, как DeleteButton использует внешний вид Button, не наследуя от него. Вместо этого Button определяет свои настраиваемые части через props, а DeleteButton предоставляет эти реквизиты. В реальном DOM и <Button />, и <DeleteButton /> будут отображаться в одном узле DOM — рекурсивное разрешение происходит во время render(), и это основная идея React.

На самом деле, если вам не нужны хуки жизненного цикла или локальное состояние, вы даже можете определить компоненты как функции:

function Button({ color, children }) {
  return (
    <div className='Button' style={{ color }}>
      {children}
    </div>
  )
}

function DeleteButton() {
  return (
    <Button color='red'>Delete</Button>
  )
}

Вы даже можете смешивать классы с функциями. Это было бы невозможно с наследованием, но прекрасно работает с композицией.

Что касается ваших конкретных случаев использования:

У меня также есть Component2, который в основном абсолютно такой же, но имеет один дополнительный <input/> внутри возврата его функции рендеринга.

Вы можете заставить свой Component1 принять this.props.children и использовать их в возвращаемом значении метода render(), а Component2 отобразить в <Component1><input /></Component>. Это очень похоже на то, что я показал выше. Вам также не нужно использовать реквизит children — вы можете передать элемент React в любом реквизите, например. <Component1 footer={<input />} />, а затем вы можете использовать this.props.footer внутри Component1.

У меня также есть Component3, который использует те же функции, но имеет другую функцию render().

Если они совместно используют какой-либо другой код (например, утилиты, вычисляющие некоторые данные), переместите этот код вне компонентов в общий модуль и импортируйте его из обоих компонентов.

Если они совместно используют какой-либо пользовательский интерфейс, извлеките его в еще один компонент и используйте его из обоих ваших компонентов.

person Dan Abramov    schedule 03.05.2016
comment
Невероятно, вы ответили на мой пост :) Сегодня я нашел ваши статьи и получил почти такое же следствие, поэтому, сидя сегодня вечером с композицией, мне просто нужно было еще несколько практических примеров. Спасибо за это объяснение и за вашу работу! Я активно использую Redux и очень им доволен. - person Battle_Slug; 03.05.2016
comment
Обычно я активно извлекаю компоненты, поэтому мой код не повторяет render часть. На самом деле мне нужен был способ использовать один и тот же код для getInitialState и других функций, которые одинаковы. Это то, что я пытаюсь сейчас. - person Battle_Slug; 03.05.2016
comment
Как вы используете обмен кодом в getInitialState? - person Dan Abramov; 06.05.2016
comment
Собственно, я сделал то, что вы сказали: у меня есть некоторый SharedComponent, поэтому я передаю ему детей с их собственными функциями. Работает отлично, код не повторяется. Наряду с этими детьми у меня есть несколько глобальных флагов в состоянии хранилища redux. SharedComponent отображается в зависимости от этих флагов. Также выбирается, какие обработчики onClick для какой-либо кнопки использовать на основе этих флагов внутри состояния redux. Это правильный путь, не так ли? Код не повторяется, и здесь у меня есть композиция. - person Battle_Slug; 06.05.2016