Реагировать - должен ли компонент высшего порядка быть записан как функция?

Я учу Реакт. Мне кажется, что HOC нравится следующий пример из официальных документов React:

function withSubscription(WrappedComponent, selectData) {
    // ...and returns another component...
    return class extends React.Component {
        constructor(props) {
            super(props);
            this.handleChange = this.handleChange.bind(this);
            this.state = {
                data: selectData(DataSource, props)
            };
        }

        componentDidMount() {
            // ... that takes care of the subscription...
            DataSource.addChangeListener(this.handleChange);
        }

        componentWillUnmount() {
            DataSource.removeChangeListener(this.handleChange);
        }

        handleChange() {
            this.setState({
                data: selectData(DataSource, this.props)
            });
        }

        render() {
            // ... and renders the wrapped component with the fresh data!
            // Notice that we pass through any additional props
            return <WrappedComponent data={this.state.data} {...this.props} />;
        }
    };
}

можно переписать следующим образом:

class WithSubscription extends React.Component {
    constructor({ component, selectData, ...props }) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
        this.state = {
            data: selectData(DataSource, props)
        };
    }

    componentDidMount() {
        DataSource.addChangeListener(this.handleChange);
    }

    componentWillUnmount() {
        DataSource.removeChangeListener(this.handleChange);
    }

    handleChange() {
        this.setState({
            data: selectData(DataSource, this.props)
        });
    }

    render() {
        return <component data={this.state.data} {...this.props} />;
    }
}

Тогда используйте это так:

<WithSubscription component={BlogPost} selectData={(DataSource) => DataSource.getComments()} />

Они оба HOC? Когда один стиль предпочтительнее другого?

3 ответа

Решение

Сначала я тоже боролся с HOC. Еще один способ взглянуть на это - обертки компонентов, которые вы можете использовать, чтобы изолировать функциональность от одного компонента.

Например, у меня есть несколько HOC. У меня есть много компонентов, которые определяются только реквизитом, и они неизменны после создания.

Затем у меня есть компонент Loader HOC, который обрабатывает все сетевые подключения, а затем просто передает реквизиты любому компоненту обертывания (это будет компонент, который вы передаете в HOC).

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

В вашем примере вы можете сделать то же самое, однако это станет намного сложнее, когда вам нужно будет объединить несколько HOC.

Например, у меня есть эта цепочка HOC:

PermissionsHOC -> LoaderHOC -> BorderLayoutHOC -> Компонент

Первый может проверить ваши разрешения, второй загружает данные, третий дает общий макет, а четвертый является фактическим компонентом.

Намного легче обнаружить HOC, если вы понимаете, что некоторые компоненты выиграли бы от наличия общей логики на родительском объекте. Вы можете сделать то же самое в своем примере, однако вам нужно будет изменять HOC каждый раз, когда вы добавляете дочерний компонент, чтобы добавить логику для этого. Не очень эффективно. Таким образом, вы можете легко добавлять новые компоненты. У меня есть компонент Base, который расширяет каждый компонент, но я использую его для обработки вспомогательных функций, таких как аналитика, регистратор, обработка ошибок и т. Д.

То, что они называют "HOC", - это, по сути, функция (обычная функция, не специфичная для React), которая ведет себя как фабрика компонентов. Это означает, что он выводит упакованные компоненты, которые являются результатом упаковки любого внутреннего компонента по вашему выбору. И ваш выбор указывается с помощью параметра "WrappedComponent". (Обратите внимание, как их так называемый "HOC" на самом деле возвращает класс).

Так что я не знаю, почему они назвали это "HOC". Это просто функция, которая выплевывает компоненты. Если кто-нибудь знает, почему мне было бы интересно услышать причину.

По сути, их пример делает именно то, что вы делаете, но он более гибкий, потому что WrappedComponent воспринимается как параметр. Таким образом, вы можете указать, что вы хотите.

С другой стороны, в вашем коде жестко закодирован ваш внутренний компонент.

Чтобы увидеть всю мощь их примера, допустим, у вас есть файл с именем insideComp.js, содержащий:

import withSubscription from './withSubscription';

class InsideComp extends React.Component{
// define it
}

export default withSubscription(InsideComp);

И когда вы используете insideComp в другом файле:

import myComp from './insideComp.js';

Вы на самом деле не импортируете insideComp, а скорее завернутую версию, которую "withSubscription" уже выплюнул. Потому что помните, что ваша последняя строка insideComp.js

export default withSubscription(InsideComp);

Таким образом, ваш InsideComp был изменен перед экспортом

Второй не HOC.

Они чеканят слово HOC из функций высшего порядка. Одним примером функции более высокого порядка является функция, которая принимает функцию в качестве аргумента и возвращает другую функцию.

Точно так же HOC - это функция, которая принимает компонент в качестве аргумента и возвращает другой компонент.

Это звучит странно для меня, потому что компонент более высокого порядка не является компонентом реакции; вместо этого это функция. Я думаю, причина, по которой они называют это HOC, заключается в том, что

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

Что касается различия между двумя стилями, которые вы упомянули:

Первый: вы бы использовали первый для генерации такого класса, как MyComponnet = withSubscription(AnotherComponent, ...)и всякий раз, когда вам это нужно в вызове рендера, просто пишите <MyComponent><MyComponent>

Второй: это не так часто. Каждый раз, когда вам это нужно в вызове рендеринга, вам нужно будет включить компонент WithSubscription, как вы упомянули в описании. <WithSubscription component={BlogPost} selectData={(DataSource) => DataSource.getComments()} />

Другие вопросы по тегам