Share This
Связаться со мной
Крути в низ
Categories
//Пиши на React в два раза быстрее! Простые трюки для крутого разработчика

Пиши на React в два раза быстрее! Простые трюки для крутого разработчика

Что делать, если скорость разработки уже не та, что раньше? Отказавшись от монолита, изменить подход к написанию кода и начать использовать его повторно! Обсудить

pishi na react v dva raza bystree prostye trjuki dlja krutogo razrabotchika 567e9ac - Пиши на React в два раза быстрее! Простые трюки для крутого разработчика

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

Вам помогут переиспользуемые блоки кода! Переиспользуемые блоки кода – то, что нужно прогрессивному разработчику!

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

Так бросим же все силы на то, чтобы научиться мыслить в компонентном стиле!

Учимся готовить компоненты

Казалось бы, каждый джун сегодня умеет писать компоненты, чему тут учиться? Но компонент компоненту рознь, для наших программ нужны только самые качественные и красивые из них. Поэтому сейчас мы возьмем неограненный React-компонент, который написал простой разработчик вроде вас, и рассмотрим его очень пристально со всех сторон. А затем много-много раз отрефакторим, пока не получится идеальный бриллиант.

Будьте готовы к многочисленным озарениям и головокружительному увеличению вашей производительности!

Исходный компонент

Рассмотрим неограненный алмаз, с которым мы будем работать. Этот простой компонент умеет не так уж и много:

  1. он получает с бэкенда список браузеров;
  2. отображает индикатор загрузки, пока запрос выполняется;
  3. выводит полученные данные в виде карточек;
  4. если пользователь нажимает на карточку, компонент показывает модальное окно с детальной информацией о браузере.

Этот код похож на ваш?

Browsers.js

         import React, { useEffect, useState } from 'react'; import { FlatList, Text, View, StyleSheet, Modal, TouchableOpacity } from 'react-native';  import AddModal from '../components/AddModal'; import LoadingIndicator from '../components/LoadingIndicator' import BrowserItem from '../components/BrowserItem'  import colors from '../config/colors';  function Browsers() {      const URL = 'https://google.com/myData.json'      // Элемент массива     // {"Browsers":[     //     {     //      "fullname": "Chrome",     //      "linkToBrowser": "https://google.com",     //      "image": "https://linktoimage.com/chrome.png",     //      "minMemory": "1 GB",     //      "currentVersion": "29.0.1",     //      "minimumRAM": "2 GB",     //      "description": "How much RAM do you have? Ha-ha",     //      "windows": true,     //      "mac": true,     //      "linux": true,     //      "ubuntu": true,     //      "fedora": false,     //      "stars": 4,     //      "id":"chrome"     //    },     // ...     // ]     // }      const [loading, setLoading] = useState(true)     const [browsers, setBrowsers] = useState([])      const [modalVisible, setModalVisible] = useState(false)     const [description, setDescription] = useState("")      const changeDescription = (description) => {         setDescription(description)         setModalVisible(!modalVisible)     }      const changeOpacity = () => {         setModalVisible(!modalVisible)         console.log('changeOpacity')     }        useEffect(() => {         fetch(URL)             .then((response) => response.json())             .then((responseJson) => {                 return responseJson.Browsers             })             .then(browsers => {                 setBrowsers(browsers)                 // console.log(browsers)                 setLoading(false)             })             .catch(error => {                 console.log(error)             })             .finally(() => setLoading(false));     }, [])       return (         <View style={styles.container}>             {loading ? (                 <LoadingIndicator />             ) : (                     <View>                         <AddModal                              modalVisible={modalVisible}                             changeOpacity = {() => changeOpacity()}                             description={description}                         />                         <FlatList                             data={browsers}                             keyExtractor={browser => browser.fullname}                             renderItem={({ item }) =>                                 <BrowserItem                                     fullname={item.fullname}                                     image={item.image}                                     linkToBrowser={item.linkToBrowser}                                     minMemory={item.minMemory}                                     currentVersion={item.currentVersion}                                     minimumRAM={item.minimumRAM}                                     description={item.description}                                     windows={item.windows}                                     mac={item.mac}                                     linux={item.linux}                                     ubuntu={item.ubuntu}                                     fedora={item.fedora}                                     stars={item.stars}                                     changeDescription={() => changeDescription(item.description)}                                 />                             }                         />                     </View>                 )             }         </View >     ); };  const styles = StyleSheet.create({     container: {         justifyContent: 'center',         alignItems: 'center'     }, })  export default Browsers;     

Что с этим компонентом так?

Ну, он работает 🙂 И использует хуки, что само по себе уже неплохо.

Что с этим компонентом не так?

Это монолит. Не получится взять его и переиспользовать в другом месте или другом приложении.

К чему мы стремимся?

Искусство быстрой разработки – это искусство создания переиспользуемых блоков кода.

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

  • Не нужно повторять одно и то же по десять раз – помним о принципе DRY!
  • Не нужно вносить изменения в нескольких местах – и лихорадочно вспоминать, где еще есть этот функционал.
  • Не нужно ловить баги по всему приложению – они смирно сидят в компоненте и ждут вас.
  • Не нужно много читать, код сразу становится короче, чище и понятнее.
  • Не нужно писать тесты для каждого места, в котором используется функциональность.

Приступаем к огранке

Начнем с самых простых приемов рефакторинга, а затем войдем во вкус и сдеаем что-то посложнее.

Шаг #1. Перенос констант в пропсы

Browsers.js

         function Browsers({url = 'https://google.com/myData.json'}) {    const URL = url   ...     

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

Шаг #2. Разделение бизнес-логики и отображения

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

В чем вообще разница?

Бизнес-логика: Код, который принимает решения и изменяет состояния. Все внутри <Browsers/> до инструкции return.

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

Давайте произведем радикальное рассечение компонента на две части и убедимся, что жизнь действительно стала проще:

  • Пользовательский хук useBrowsers() с бизнес-логикой.
  • Компонент <BrowsersList /> с логикой отображения.

Browsers_splitted.js

         import React, {useEffect, useState} from 'react' import {FlatList, StyleSheet, View} from 'react-native'  import AddModal from '../components/AddModal' import LoadingIndicator from '../components/LoadingIndicator' import BrowserItem from '../components/BrowserItem'  const styles = StyleSheet.create({   container: {     justifyContent: 'center',     alignItems: 'center',   }, })  function useBrowsers(url) {   const [loading, setLoading] = useState(true)   const [browsers, setBrowsers] = useState([])    const [modalVisible, setModalVisible] = useState(false)   const [description, setDescription] = useState('')    const changeDescription = (description) => {     setDescription(description)     setModalVisible(!modalVisible)   }    const changeOpacity = () => {     setModalVisible(!modalVisible)     console.log('changeOpacity')   }    useEffect(() => {     fetch(URL)       .then((response) => response.json())       .then((responseJson) => {         return responseJson.Browsers       })       .then((browsers) => {         setBrowsers(browsers)         // console.log(browsers)         setLoading(false)       })       .catch((error) => {         console.log(error)       })       .finally(() => setLoading(false))   }, [])    return {     loading,     browsers,     modalVisible,     description,     changeDescription,     changeOpacity,   } }  function BrowsersList({   loading,   browsers,   modalVisible,   description,   changeDescription,   changeOpacity, }) {   return (     <View style={styles.container}>       {loading ? (         <LoadingIndicator />       ) : (         <View>           <AddModal             modalVisible={modalVisible}             changeOpacity={() => changeOpacity()}             description={description}           />           <FlatList             data={browsers}             keyExtractor={(browser) => browser.fullname}             renderItem={({item}) => (               <BrowserItem                 fullname={item.fullname}                 image={item.image}                 linkToBrowser={item.linkToBrowser}                 minMemory={item.minMemory}                 currentVersion={item.currentVersion}                 minimumRAM={item.minimumRAM}                 description={item.description}                 windows={item.windows}                 mac={item.mac}                 linux={item.linux}                 ubuntu={item.ubuntu}                 fedora={item.fedora}                 stars={item.stars}                 changeDescription={() => changeDescription(item.description)}               />             )}           />         </View>       )}     </View>   ) }  function Browsers() {   return <BrowsersList {...useBrowsers('https://google.com/myData.json')} /> }  export default Browsers     

Код все еще далек от идеала, но уже стал немного более удобным.

  • <BrowsersList /> теперь можно использовать с разными источниками данных (а не только с данными из HTTP-эндпоинтов).
  • useBrowsers() теперь может работать с разными представлениями или даже вообще без представления. Если вы измените дизайн приложения, этот хук продолжит работать.

Шаг #3. Разделение на файлы

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

pishi na react v dva raza bystree prostye trjuki dlja krutogo razrabotchika 49813f8 - Пиши на React в два раза быстрее! Простые трюки для крутого разработчика

Это файловая структура типичного React-проекта:

  1. index.js экспортирует <Browsers/> из Browsers.jsx;
  2. строительные блоки для <Browsers/> лежат в папках components и hooks;

BrowsersList.jsx можно развить до самостоятельной папки с собственными хуками, компонентами и файлом index.js

pishi na react v dva raza bystree prostye trjuki dlja krutogo razrabotchika 1b91126 - Пиши на React в два раза быстрее! Простые трюки для крутого разработчика

Посмотрим на BrowsersList.jsx:

         import React from 'react' import {FlatList, StyleSheet, View} from 'react-native' import AddModal from '../../../components/AddModal' import LoadingIndicator from '../../../components/LoadingIndicator' import BrowserItem from '../../../components/BrowserItem'  const styles = StyleSheet.create({   container: {     justifyContent: 'center',     alignItems: 'center',   }, })  export function BrowsersList({   loading,   browsers,   modalVisible,   description,   changeDescription,   changeOpacity, }) {   return (     <View style={styles.container}>       {loading ? (         <LoadingIndicator />       ) : (         <View>           <AddModal             modalVisible={modalVisible}             changeOpacity={() => changeOpacity()}             description={description}           />           <FlatList             data={browsers}             keyExtractor={(browser) => browser.fullname}             renderItem={({item}) => (               <BrowserItem                 fullname={item.fullname}                 image={item.image}                 linkToBrowser={item.linkToBrowser}                 minMemory={item.minMemory}                 currentVersion={item.currentVersion}                 minimumRAM={item.minimumRAM}                 description={item.description}                 windows={item.windows}                 mac={item.mac}                 linux={item.linux}                 ubuntu={item.ubuntu}                 fedora={item.fedora}                 stars={item.stars}                 changeDescription={() => changeDescription(item.description)}               />             )}           />         </View>       )}     </View>   ) }     

Этот код уже почти помещается в один экран вашего редактора. Меньше хлама – легче читать!

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

Большая проблема маленьких файлов

Взгляните на сигнатуру функции <BrowsersList />. Что произойдет, если мы переименуем какой-нибудь пропс, например, changeDescription на setSelectedBrowser? Или удалим аргумент? Или добавим новый?

Все сломается!

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

Ну и где профит-то, спросите вы? Опять что-нибудь где-нибудь забудем исправить – и прощай продакшн.

Посмотрите внимательно, все ли тут в порядке?

Файл useBrowsers.js:

         ... return {     loading,     browsers,     modalVisible,     descripton,     changeDescription,     changeOpacity,   } ...     

Файл BrowsersList.jsx:

         ... export function BrowsersList({   loading,   browsers,   modalVisible,   description,   changeDescription,   changeOpacity, }) { ....     

Бинго! Одна маленькая опечатка – и все идет кувырком.

Сколько прекрасных часов проводят молодые разработчики, сравнивая пропсы и пытаясь понять, что же сломалось – но мы-то с вами уже не такие! Давайте решать проблему радикально.

Хватит медленно кодить на JS, давайте кодить быстро на TS

В 2021 году у вас нет оправданий, если вы не используете TypeScript. Вам даже не требуется сразу же изучить все его возможности, ведь можно просто добавить TS в проект, не меняя ни строчки, и постепенно наращивать его применение.

pishi na react v dva raza bystree prostye trjuki dlja krutogo razrabotchika 2758492 - Пиши на React в два раза быстрее! Простые трюки для крутого разработчика

38% багов на Airbnb можно было предотвратить с помощью TypeScript

С TypeScript ваша IDE обогатится несколькими крутыми фичами:

  • Автодополнение для пропсов

pishi na react v dva raza bystree prostye trjuki dlja krutogo razrabotchika b754781 - Пиши на React в два раза быстрее! Простые трюки для крутого разработчика

  • Возможность автоматического переименования пропсов
  • Проверка на null/undefined

pishi na react v dva raza bystree prostye trjuki dlja krutogo razrabotchika bfbe81b - Пиши на React в два раза быстрее! Простые трюки для крутого разработчика

  • Валидация значений пропсов

pishi na react v dva raza bystree prostye trjuki dlja krutogo razrabotchika a8ee978 - Пиши на React в два раза быстрее! Простые трюки для крутого разработчика

TypeScript сэкономит вам тонну времени и километры нервов.

А вот, кстати, и наша опечатка:

pishi na react v dva raza bystree prostye trjuki dlja krutogo razrabotchika 5c27528 - Пиши на React в два раза быстрее! Простые трюки для крутого разработчика

Шаг #4. Определение типов

Так как это не полноценный гайд по TypeScript, разбираться в основах мы сейчас не будем. Все желающие могут заглянуть на typescriptlang.org (или прочитать статью в «Библиотеке программиста» – прим. ред.). Вернемся к <BrowsersList /> и преобразуем его пропсы в симпатичные типы (не забудьте сменить расширение с .jsx на .tsx).

BrowsersList_props_types.tsx

         // ...  export type Browser = {   fullname: string // ожидается, что поле "fullname" - это строка   image: string   linkToBrowser: string   minMemory: string   currentVersion: string   minimumRAM: string   description: string   windows: boolean   mac: boolean   linux: boolean   ubuntu: boolean   fedora: boolean   stars: number }  export type BrowsersListProps = {   loading: boolean   browsers: Browser[] // ожидается, что поле "browsers" это массив элементов с типом Browser   modalVisible: boolean   description: string      // ожидается, что changeDescription - это функция   // которая принимает строку и ничего не возвращает   changeDescription: (description: string) => void      // ожидается, что changeOpacity - это функция   // которая ничего не принимает и ничего не возвращает   changeOpacity: () => void }  export function BrowsersList({   loading,   browsers,   modalVisible,   description,   changeDescription,   changeOpacity, }: BrowsersListProps) {   return (  // ...     

Теперь обновим сигнатуру useBrowsers():

useBrowsers.ts

         import {useEffect, useState} from 'react' import {BrowsersListProps} from '../components/BrowsersList'  export function useBrowsers(url: string): BrowsersListProps {   const [loading, setLoading] = useState(true)     // ...     

И теперь TypeScript будет строго следить, чтобы useBrowsers() и BrowsersList были совместимы.

Быстрая разработка архитектуры

BrowsersListProps выглядит весьма нагруженно:

props.tsx

         export type BrowsersListProps = {   loading: boolean   browsers: Browser[]   modalVisible: boolean   description: string   changeDescription: (description: string) => void   changeOpacity: () => void }     
  • Одна строчка – для состояния загрузки.
  • Одна строчка – для списка браузеров.
  • Целых четыре строчки – для отображения детальной информации о браузере в модальном окне. Есть большая вероятность, что потребуется выводить больше данных, а значит сигнатура может измениться. А это весьма беспокойное дело, как мы помним.

Мы можем уменьшить сложность этого фрагмента и отрефакторить функциональность модального окна для использования типа Browser:

pishi na react v dva raza bystree prostye trjuki dlja krutogo razrabotchika 09ed38f - Пиши на React в два раза быстрее! Простые трюки для крутого разработчика

TypeScript указывает на некорректность сигнатуры при ее изменении

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

Теперь поправим <BrowserList />, чтобы он мог работать с новой сигнатурой BrowsersListProps.

Отрефакторим <BrowserItem />. Сейчас он принимает множество пропсов, и это явный сигнал для внесения правок. Теперь он будет принимать всего 2 аргумента:

BrowsersList.tsx

         import React from 'react' import {FlatList, StyleSheet, View} from 'react-native' import AddModal from '../../../components/AddModal' import LoadingIndicator from '../../../components/LoadingIndicator' import BrowserItem from '../../../components/BrowserItem'  const styles = StyleSheet.create({   container: {     justifyContent: 'center',     alignItems: 'center',   }, })  export type Browser = {   fullname: string   image: string   linkToBrowser: string   minMemory: string   currentVersion: string   minimumRAM: string   description: string   windows: boolean   mac: boolean   linux: boolean   ubuntu: boolean   fedora: boolean   stars: number }  export type BrowsersListProps = {   loading: boolean   browsers?: Browser[]   selectedBrowser?: Browser   setSelectedBrowser: (browser?: Browser) => void }  export function BrowsersList(props: BrowsersListProps) {   const {loading, selectedBrowser, setSelectedBrowser, browsers} = props   return (     <View style={styles.container}>       {loading ? (         <LoadingIndicator />       ) : (         <View>           <AddModal             modalVisible={Boolean(selectedBrowser)}             onClose={() => setSelectedBrowser(undefined)}             description={selectedBrowser?.description}           />           <FlatList             data={browsers}             keyExtractor={(browser) => browser.fullname}             renderItem={({item}) => (               <BrowserItem                 browser={item}                 onPress={() => setSelectedBrowser(item)}               />             )}           />         </View>       )}     </View>   ) }     

Компонент стал проще и надежнее.

Шаг #5. Извлечение <UIFriendlyList />

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

Сейчас эта функциональность интегрирорована в <BrowsersList />. Значит надо ее извлечь. Создадим новый компонент <UIFriendlyList /> и будем использовать его вместо простого <FlatList/ >.

Как всегда начнем с определения типов:

         type UIFriendlyListProps<T> = FlatListProps<T> & {loading?: boolean}      
  • T – это аргумент типа, или дженерик. То же самое, что arg в сигнатуре foo(arg). Дженерики нужны, если вы хотите создать свой тип из другого типа. Вот здесь есть подробнейшее описание дженериков.
  • & – это символ пересечения множеств (интерсекция). Тип X = A & B означает, что X содержит в себе свойства A и B.

Итак, что мы сделали:

  • Определили тип для пропсов нового компонента.
  • Использовали дженерик, чтобы указать, что список может содержать элементы разных типов.
  • UIFriendlyListProps расширяет встроенные класс FlatListProps из библиотеки React Native и добавляет в него состояние загрузки.

Теперь вынесем новый компонент в отдельный файл UIFriendlyList.jsx:

UIFriendlyList.tsx

         import React from 'react' import {FlatList, FlatListProps, Text} from 'react-native' import LoadingIndicator from './LoadingIndicator'  export type UIFriendlyListProps<T> = FlatListProps<T> & {loading?: boolean}  export function UIFriendlyList<T>(props: UIFriendlyListProps<T>) {   if (props.loading) {     return <LoadingIndicator />   }    if (props?.data && props.data.length === 0) {     return <Text>This list is empty (</Text>   }    return <FlatList {...props} /> }     

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

Компонент <UIFriendlyList /> – это крутой строительный блок, который очень легко переиспользовать в самых разных ситуациях. Добавьте его в свою коллекцию кирпичиков, чтобы стать еще быстрее.

Во что теперь превратился наш <BrowsersList />:

BrowsersList.tsx

         import React from 'react' import {StyleSheet, View} from 'react-native' import AddModal from '../../../components/AddModal' import BrowserItem from '../../../components/BrowserItem' import {UIFriendlyList} from '../../../components/UIFriendlyList'  const styles = StyleSheet.create({   container: {     justifyContent: 'center',     alignItems: 'center',   }, })  export type Browser = {   fullname: string   image: string   linkToBrowser: string   minMemory: string   currentVersion: string   minimumRAM: string   description: string   windows: boolean   mac: boolean   linux: boolean   ubuntu: boolean   fedora: boolean   stars: number }  export type BrowsersListProps = {   loading: boolean   browsers?: Browser[]   selectedBrowser?: Browser   setSelectedBrowser: (browser?: Browser) => void }  export function BrowsersList(props: BrowsersListProps) {   const {loading, selectedBrowser, setSelectedBrowser, browsers} = props   return (     <View style={styles.container}>       <AddModal         modalVisible={Boolean(selectedBrowser)}         onClose={() => setSelectedBrowser(undefined)}         description={selectedBrowser?.description}       />       <UIFriendlyList         loading={loading}         data={browsers}         renderItem={({item}) => (           <BrowserItem             key={item.fullname}             browser={item}             onPress={() => setSelectedBrowser(item)}           />         )}       />     </View>   ) }     

Сравните его с исходным вариантом. Он почти в два раза меньше и гораздо проще для понимания. К тому же в качестве бонуса вы получили отличный компонент <UIFriendlyList />, который в будущем сэкономит вам кучу времени. Можно пойти еще дальше и выделить, например, в отдельный кирпичик логику Модальное Окно со Списком, но давайте пока остановимся.

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

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

Шаг #6. Рефакторинг useBrowsers()

Хук useBrowswers() должен возвращать валидный объект с типом BrowsersListProps:

useBrowsers.ts

         import {useEffect, useState} from 'react' import {Browser, BrowsersListProps} from '../components/BrowsersList'  export function useBrowsers(url: string): BrowsersListProps {   const [loading, setLoading] = useState(false)   const [browsers, setBrowsers] = useState<Browser[]>([])   const [selectedBrowser, setSelectedBrowser] = useState<Browser | undefined>(     undefined,   )    useEffect(() => {     setLoading(true)     fetch(url)       .then((response) => response.json())       .then((responseJson) => {         return responseJson.Browsers       })       .then((browsers) => {         setBrowsers(browsers)       })       .catch((error) => {         console.log(error)       })       .finally(() => setLoading(false))   }, [url])    return {     loading,     browsers,     selectedBrowser,     setSelectedBrowser,   } }     

Приглядимся повнимательнее. Функциональность “обратиться по некоторому URL и сохранить результат запроса, пока отображается индикатор загрузки” кажется весьма полезной, давайте извлечем ее в новый хук useFetch.

Как всегда, сначала типы. Нам нужно, чтобы useFetch сохранял данные из эндпоинта и отображал состояние загрузки. Формат данных будет задан отдельно, для этого используем дженерик:

useFetch.ts

         export type FetchBrowsersResults = {   Browsers: Browser[] }  export type UseFetch<T> = {   loading: boolean      // We use Generic. T - is a type argument that can be any type.   // We can useFetch() with any type   // ? means, that T can be undefined   data?: T }  export function useFetch<T>(url: string): UseFetch<T> {}     

Таким образом, useFetch можно будет использовать с любыми типами данных.

Теперь сама функция:

useFetch.ts

         import {useEffect, useState} from 'react' import {Alert} from 'react-native'  export type UseFetch<T> = {   loading: boolean   data?: T  }  export function useFetch<T>(url: string): UseFetch<T> {   const [loading, setLoading] = useState<boolean>(false)   const [data, setData] = useState<T | undefined>(undefined)    useEffect(() => {     setLoading(true)     fetch(url)       .then((response) => response.json())       .then(setData)       .finally(() => setLoading(false))       .catch((error) => Alert.alert('Fetch error', error))   }, [url])    return {     loading,     data,   } }     

Для полноты картины добавили Alert при ошибке запроса.

Теперь окончательно отрефакторим useBrowsers():

useBrowsers.ts

         import {useState} from 'react' import {Browser, BrowsersListProps} from '../components/BrowsersList' import {useFetch} from '../../../hooks/useFetch'  export type FetchBrowsersResults = {   Browsers: Browser[] }  export function useBrowsers(url: string): BrowsersListProps {   const {loading, data} = useFetch<FetchBrowsersResults>(url)   const [selectedBrowser, setSelectedBrowser] = useState<Browser | undefined>(     undefined,   )    return {     loading,     browsers: data?.Browsers,     selectedBrowser,     setSelectedBrowser,   } }     

Сравните с исходным вариантом.

Кажется, здесь больше нечего извлекать 🙂

4 простых совета для ускорения разработки

1. Никогда не форматируйте код вручную.

Используйте возможности IDE, ESLint и Prettier.

pishi na react v dva raza bystree prostye trjuki dlja krutogo razrabotchika 7160c4e - Пиши на React в два раза быстрее! Простые трюки для крутого разработчика

2. Никогда не импортируйте модули вручную

Использование автоматического импорта сэкономит много времени.

pishi na react v dva raza bystree prostye trjuki dlja krutogo razrabotchika ae2fde5 - Пиши на React в два раза быстрее! Простые трюки для крутого разработчика

3. Научитесь ориентироваться среди множества файлов

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

pishi na react v dva raza bystree prostye trjuki dlja krutogo razrabotchika ab91cbd - Пиши на React в два раза быстрее! Простые трюки для крутого разработчика

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

4. Используйте линтинг

Это поможет найти самые хитрые и вредные ошибки:

pishi na react v dva raza bystree prostye trjuki dlja krutogo razrabotchika 9dd251f - Пиши на React в два раза быстрее! Простые трюки для крутого разработчика

***

Искусство быстрой разработки

Чтобы быть быстрым, не потеряв при этом в качестве, вам нужно освоить несколько вещей:

  • Отделять бизнес-логику от отображения.
  • Разделять код на маленькие реюзабельные компоненты.
  • Использовать TypeScript и начинать работу с определения типов.
  • Практиковаться в рефакторинге.
  • Использовать плюшки вашей IDE.

Насколько вы постигли дзен быстрой разработки? Признавайтесь, часто рефакторите?

Дополнительные материалы:

  • Самоучитель для начинающих: как освоить TypeScript с нуля за 30 минут?
  • Демистификация хуков React: useCallback, useMemo и все-все-все
  • 8 мощных библиотек React, которые стоит попробовать в 2021 году
  • 33 приема оптимизации JavaScript, которые вы должны знать в 2021 году

  • 4 views
  • 0 Comment

Leave a Reply

Ваш адрес email не будет опубликован.

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Свежие комментарии

    Рубрики

    About Author 01.

    blank
    Roman Spiridonov

    Моя специальность - Back-end Developer, Software Engineer Python. Мне 39 лет, я работаю в области информационных технологий более 5 лет. Опыт программирования на Python более 3 лет. На Django более 2 лет.

    Categories 05.

    © Speccy 2022 / All rights reserved

    Связаться со мной
    Close