Разработка сайтов в Белгороде. Компоненты высшего порядка: шаблон проектирования приложений React

 
 

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

Чистые функции

Функция считается чистой, если она обладает следующими свойствами:

все данные, с которыми он работает, объявлены как аргументы

он не мутирует данные, которые ему дали, или любые другие данные (это часто называют побочными эффектами)

при одном и том же входе он всегда будет возвращать один и тот же результат.

Например, addфункция ниже чистая:

function add (x, y) {

return x + y;

}

Однако функция badAddниже нечиста:

let y = 2;

function badAdd (x) {

return x + y;

}

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

let y = 2;

badAdd (3) // 5

y = 3;

badAdd (3) // 6

Чтобы узнать больше о чистых функциях, вы можете прочитать «Введение в разумно чистое программирование «Марка Брауна.

Хотя чистые функции очень полезны и значительно упрощают отладку и тестирование приложения, иногда вам нужно создавать нечистые функции, которые имеют побочные эффекты, или изменять поведение существующей функции, к которой вы не можете получить прямой доступ (функция из библиотеки, например). Чтобы включить это, нам нужно взглянуть на функции более высокого порядка.

Функции высшего порядка

Функция высшего порядка — это функция, которая при вызове возвращает другую функцию. Часто они также принимают функцию в качестве аргумента, но это не требуется для того, чтобы функция считалась более высокого порядка.

Допустим, у нас есть наша addфункция сверху, и мы хотим написать некоторый код, чтобы при ее вызове мы записывали результат в консоль перед возвратом результата. Мы не можем редактировать addфункцию, поэтому вместо этого мы можем создать новую функцию:

function addAndLog (x, y) {

const result = add (x, y) ;

console.log (`Result: ${result}`) ;

return result;

}

Мы решили, что регистрация результатов функций полезна, и теперь мы хотим сделать то же самое с subtractфункцией. Вместо того, чтобы дублировать приведенное выше, мы могли бы написать функцию более высокого порядка, которая может принимать функцию и возвращать новую функцию, которая вызывает данную функцию и регистрирует результат, прежде чем возвращать его:

function logAndReturn (func) {

return function (...args) {

const result = func (...args)

console.log (‘Result’, result) ;

return result;

}

}

Теперь мы можем взять эту функцию и использовать ее для добавления логирования в addи subtract:

const addAndLog = logAndReturn (add) ;

addAndLog (4, 4) // 8 is returned, «Result 8’ is logged

const subtractAndLog = logAndReturn (subtract) ;

subtractAndLog (4, 3) // 1 is returned, «Result 1’ is logged;

logAndReturnявляется функцией высшего порядка, потому что она принимает функцию в качестве аргумента и возвращает новую функцию, которую мы можем вызвать. Они действительно полезны для обертывания существующих функций, поведение которых вы не можете изменить. Дополнительную информацию об этом можно найти в статье М. Дэвида Грина «Функции высшего порядка в JavaScript «, в которой эта тема рассматривается гораздо подробнее.

Компоненты высшего порядка

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

Примечание: с появлением React Hooks, выпущенного в React 16.8, функции более высокого порядка стали немного менее полезными, поскольку хуки позволяли делиться поведением без необходимости в дополнительных компонентах. Тем не менее, они по-прежнему являются полезным инструментом, который нужно иметь на поясе.

В этом разделе мы собираемся использовать React Router, решение маршрутизации де-факто для React. Если вы хотите начать работу с библиотекой, я настоятельно рекомендую документацию React Router как лучшее место для начала.

Компонент React Router Link

React Router предоставляет компонент, который используется для связи между страницами в приложении React. Одним из свойств, которое принимает этот компонент, является activeClassName. Когда у объекта есть это свойство и оно в данный момент активно (пользователь находится на URL-адресе, на который указывает ссылка), компоненту будет присвоен этот класс, что позволит разработчику стилизовать его.

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

Home

About

Contact

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

Вместо этого мы можем написать компонент, который обертывает компонент:

const AppLink = (props) => {

return (

{props.children}

 

) ;

};

И теперь мы можем использовать этот компонент, который приводит в порядок наши ссылки:

Home

About

Contact

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

Улучшенные компоненты высшего порядка

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

Принятие нескольких свойств

Компонент ожидает два свойства:

this.props.to, который является URL-адресом, по которому пользователь должен перейти по ссылке

this.props.children, который представляет собой текст, отображаемый пользователю

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

Распространение JSX

JSX, HTML-подобный синтаксис, который мы используем для определения элементов React, поддерживает оператор распространения для передачи объекта компоненту в качестве свойств. Например, примеры кода ниже достигают того же самого:

const props = { a: 1, b: 2};

Использование {...props}распространяет каждый ключ в объекте и передает его Fooкак отдельное свойство.

Мы можем использовать этот трюк с поддержкой любого произвольного свойства, которое поддерживает. Делая это, мы также защищаем себя в будущем; если в будущем будут добавлены какие-либо новые свойства, наш компонент-оболочка уже будет их поддерживать.

const AppLink = (props) => {

return ;

}

Теперь будет принимать любые свойства и передавать их. Обратите внимание, что мы также можем использовать самозакрывающуюся форму вместо явных ссылок {props.children}между тегами. React позволяет childrenпередавать как обычную опору или как дочерние элементы компонента между открывающим и закрывающим тегом.

Порядок свойств в React

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

Special Secret Link

Однако это не работает. Причина в том, что свойства упорядочиваются при рендеринге компонента:

return

;

Когда у вас есть одно и то же свойство несколько раз в компоненте React, выигрывает последнее объявление. Это означает, что наше последнее activeClassName="active-link"объявление всегда будет выигрывать, так как оно размещено после {...this.props}. Чтобы исправить это, мы можем изменить порядок свойств, чтобы мы распространялись this.propsпоследними. Это означает, что мы устанавливаем разумные значения по умолчанию, которые хотели бы использовать, но пользователь может переопределить их, если ему действительно нужно:

return

;

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

Создатели компонентов высшего порядка

Часто у вас будет ряд компонентов, которые вам нужно обернуть одним и тем же поведением. Это очень похоже на ранее в этой статье, когда мы обернули addи subtractдобавили к ним ведение журнала.

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

Способ решить эту проблему — создать функцию, которую мы можем вызывать с помощью компонента React. Затем функция вернет новый компонент React, который будет отображать данный компонент, но с дополнительным свойством, которое даст ему доступ к информации о пользователе.

Звучит довольно сложно, но с помощью кода это можно упростить:

function wrapWithUser (Component) {

// information that we don’t want everything to access

const secretUserInfo = {

name: ‘Jack Franklin’,

favouriteColour: ‘blue’

};

// return a newly generated React component

// using a functional, stateless component

return function (props) {

// pass in the user variable as a property, along with

// all the other props that we might be given

return

}

}

Функция берет компонент React (что легко заметить, поскольку компоненты React обычно имеют заглавные буквы в начале) и возвращает новую функцию, которая отрисовывает компонент, который ей был передан, с дополнительным свойством user, для которого задано значение secretUserInfo.

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

const AppHeader = function (props) {

if (props.user) {

return Logged in as {props.user.name};

} else {

return You need to login;

}

}

Последний шаг — подключить этот компонент так, чтобы он получил this.props.user. Мы можем создать новый компонент, передав его в нашу wrapWithUserфункцию:

const ConnectedAppHeader = wrapWithUser (AppHeader) ;

Теперь у нас есть компонент, который можно визуализировать и который будет иметь доступ к userобъекту.

Я решил назвать компонент, ConnectedAppHeaderпотому что думаю о нем как о связанном с каким-то дополнительным фрагментом данных, доступ к которому есть не у каждого компонента.

Этот шаблон очень распространен в библиотеках React, особенно в Redux, поэтому знание того, как он работает и почему он используется, поможет вам по мере роста вашего приложения, и вы полагаетесь на другие сторонние библиотеки, которые используют этот подход.

Вывод

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

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

3D-печать5GABC-анализAndroidAppleAppStoreAsusCall-центрChatGPTCRMDellDNSDrupalExcelFacebookFMCGGoogleHuaweiInstagramiPhoneLinkedInLinuxMagentoMicrosoftNvidiaOpenCartPlayStationPOS материалPPC-специалистRuTubeSamsungSEO-услугиSMMSnapchatSonyStarlinkTikTokTwitterUbuntuUp-saleViasatVPNWhatsAppWindowsWordPressXiaomiYouTubeZoomАвдеевкаАктивные продажиАкцияАлександровск ЛНРАлмазнаяАлчевскАмвросиевкаАнализ конкурентовАнализ продажАнтимерчандайзингАнтрацитАртемовскАртемовск ЛНРАссортиментная политикаБелгородБелицкоеБелозерскоеБердянскБизнес-идеи (стартапы)БрендБрянкаБукингВахрушевоВендорВидеоВикипедияВирусная рекламаВирусный маркетингВладивостокВнутренние продажиВнутренний маркетингВолгоградВолновахаВоронежГорловкаГорнякГорскоеДебальцевоДебиторкаДебиторская задолженностьДезинтермедитацияДзержинскДивизионная система управленияДизайнДимитровДирект-маркетингДисконтДистрибьюторДистрибьюцияДобропольеДокучаевскДоменДружковкаЕкатеринбургЕнакиевоЖдановкаЗапорожьеЗимогорьеЗолотоеЗоринскЗугрэсИжевскИловайскИрминоКазаньКалининградКировскКировскоеКомсомольскоеКонстантиновкаКонтент-маркетингКонтент-планКопирайтингКраматорскКрасноармейскКрасногоровкаКраснодарКраснодонКраснопартизанскКрасный ЛиманКрасный ЛучКременнаяКураховоКурскЛисичанскЛуганскЛутугиноМакеевкаМариупольМаркетингМаркетинговая информацияМаркетинговые исследованияМаркетинговый каналМаркетинг услугМаркетологМарьинкаМедиаМелекиноМелитопольМенеджментМерчандайзерМерчандайзингМиусинскМолодогвардейскМоскваМоспиноНижний НовгородНиколаевНиколаевкаНишевой маркетингНовоазовскНовогродовкаНоводружескНовосибирскНумерическая дистрибьюцияОдессаОмскОтдел маркетингаПартизанский маркетингПервомайскПеревальскПетровскоеПлата за кликПоисковая оптимизацияПопаснаяПравило ПаретоПривольеПрогнозирование продажПродвижение сайтов в ДонецкеПроизводство видеоПромоПромоушнПрямой маркетингРабота для маркетологаРабота для студентаРазработка приложенийРаспродажаРегиональные продажиРекламаРеклама на асфальтеРемаркетингРетро-бонусРибейтРитейлРовенькиРодинскоеРостов-на-ДонуРубежноеСамараСанкт-ПетербургСаратовСватовоСвердловскСветлодарскСвятогорскСевастопольСеверодонецкСеверскСедовоСейлз промоушнСелидовоСимферопольСинергияСколковоСлавянскСнежноеСоздание сайтов в ДонецкеСоледарСоциальные сетиСочиСтаробельскСтаробешевоСтахановСтимулирование сбытаСуходольскСчастьеТелемаркетингТельмановоТираспольТорговый представительТорезТрейд маркетингТрейд промоушнТюменьУглегорскУгледарУкраинскХабаровскХарцызскХерсонХостингЦелевая аудиторияЦифровой маркетингЧасов ЯрЧелябинскШахтерскЮжно-СахалинскЮнокоммунаровскЯндексЯсиноватая