5 нояб. 2014 г.

Повторное использование кода в React

В React отсутствует какое-либо наследование компонентов, так что если необходимо реализовать несколько компонентов с похожим функционалом (и одинаковым кодом), и избежать копирования общего кода, то для этого существует только два способа повторного использования кода:
  1. Mixin (docs)
  2. Компонент-обёртка

Mixin

Например, мы хотим одинаковым образом обрабатывать реакцию на мышь у разных компонентов.

var Sortable = {
    componentDidMount: function() {
        this._clearSortState();
    },
    sortMouseDown: function(event) {
        this.sortableMouseDownTarget = event.target;
    },
    ...
    sortEnd: function() {
        ...
        if (this._isDropFinished) {
            this.sortItems(this.sortState.key, this.sortState.overKey, this.sortState.placeAfter);
        }
        ...
    }
};

var SomeComponent = React.createClass({
    mixins: [Sortable],
    componentDidMount: function() {
        ...
    },
    sortItems: function(key, overKey, placeAfter) {
        ...
    },
    render: function() {
        return <div onMouseDown={this.sortMouseDown}>...</div>;
    }
});

var SomeOtherComponent = React.createClass({
    mixins: [Sortable],
    sortItems: function(key, overKey, placeAfter) {
        ...
    },
    render: function() {
        return <ul onMouseDown={this.sortMouseDown}>...</ul>;
    }
});


Особенности:
  • Стандартные методы цикла жизни (componentDidMount, componentWillUnmount и т.п.) не перезатираются, а объединяются с такими же методами в компоненте, т.е. если и у компонента и у использованных миксинов есть метод componentDidMount, то все они будут вызваны по очереди: сначала методы миксинов в том порядке, в котором миксины были указаны в массиве mixins, затем метод собственно компонента.
  • Все прочие имена полей/методов в миксине должны быть уникальными, т.е. если и миксин и использующий его компонент будут содержать метод sortMouseDown, то React сообщит об ошибке в консоли браузера.
  • Не создаёт никаких дополнительных элементов и уровней вложенности.

Элемент-обёртка

Например, подгрузка бесконечного списка при прокрутке вниз.

var InfiniteScroll = React.createClass({
    componentDidMount: function() {
        this.attachScrollListener();
    },
    componentDidUpdate: function() {
        this.attachScrollListener();
    },
    render: function() {
        var props = this.props;
        return React.DOM.div(null, props.children, props.hasMore && props.loader);
    },
    scrollListener: function() {
        ...
        if (scrollParent.scrollHeight - $(scrollParent).scrollTop() - $(scrollParent).height() < this.props.threshold) {
            this.props.loadMore(this.pageLoaded += 1);
        }
    },
    ...
    componentWillUnmount: function() {
        this.detachScrollListener();
    }
});

var MyEndlessList = React.createClass({
    loadMore: function(page) {
        ...
    },
    ...
    render: function() {
        return (
            <div style={{maxHeight: '500px', overflowY: 'auto'}}>
                <InfinityScroll
                    ref="scroll"
                    loadMore={this.loadMore}
                    hasMore={this.state.hasMore}>
                    {this.state.items}
                </InfinityScroll>
            </div>
            );
    }
});

Особенности:

  • Лишний уровень вложенности как в JSX, так и в DOM.
  • Все необходимые параметры и настройки обёртки собраны в одном месте - в атрибутах обёртки.
  • Проблемы конфликта имён, как в миксине, не существует в принципе.

Комментариев нет:

Отправить комментарий