Стварэнне чытальні PDF, стойкай да збоев, для большых дакументаў у React Native
Выучыце архітектуру для адрабатавання вельмі большых PDF-файлов з тыячамі сторанак, створанных у React Native, з системай адкладзеных заклейкі, возможнасцю пошуку і стабільным навігацыяй на прасоўскапрацоўных прыстроях.
Крыніцы: Rendering and Navigating Large PDFs in React Native Without Crashing the App
П’яхостранічны PDF лёгкаа прадстаўляць на экране ў аплікацыі React Native. Аднак дакумент, які складаецца з сотняў чы роўна тысяч сторанак, мае глэбокая роўневая структуру закладак і внутршнія звязкі межа фрагментамі, ёсць сапраўдна іншыя вызванне — такая аплікацыя можа быстра стаць медленной, неадказнаю чы нават часта зупіняцца на менш моцных прыстроях. У гэтым кяліку прадстаўлены методы, якія безпасебна рашаюць гэтыя проблемы: эфективная візуалізацыя большых PDF, можлівасць перайсця на будзь-якую сторанку, працэўванне з роўневаяя структура закладак і падтрымка стабільнасці ўсьго прыстрою нават на простых устатаўленнях.
У аднам з тэстоў быў выкарыстан PDF з 1 900 сторанак, які меў роўневаяя структуру закладак з многаю колькасцю роўнаў. Прабаўка адразу паказаць усю гэтую структуру вызвала серйозны навантажэнне на памяць. У наступных раздзелах описаны падходы, якія дапамоглі рашыць гэтыя проблемы.
Што react-native-pdf дае — і чаго не дае
Перш чым выбіраць дапаможныя бібліятэкі, важна точна знаты, дзе заканчваюцца вбудованыя можлівасці react-native-pdf, таму што гэтыя межы вплываюць на всю структуру рашэння:
- За дапомогою свайго калебака
onLoadCompleteён дае первісную інфармацыю пра закладкі (через параметрtableContents) на iOS і Android — але не на Windows, і точна не у формате, які можна было б безпосередня прадстаўіць на экране. Цэй ёсць первісны, неструктураваны дадзеныя, якія все ўсё трэба парасаваць і адрасаваць на вашай стороне. - Ён дае універсальны калебак для адпаведзення на нажатыя на лінкі (
onPressLink), але гэты калебак не можа розразіць внутранія переходы ў дакумэнті ад зовнішніх URL-адрэс, і ён не завжды надае правільны номер сторонкі для внутраніх лінкаў.
У зв’язку з гэтым практычны спосаб прытворнага, крос-платформовага зберагачча інфармацыі прысвячэнняў та спакаяў — гэта выкарыстоўваць яе незалежна, а не паследаваць первісны выхід функцыі вызову рэндерара — і самэ гэтае адпавядае ролі pdf-lib, пра якую будзе говорыцца далей. Цяная архітектура не ставить за мету шуканне тексту ў самым кантэнце PDF; яна займаецца шуканнем тэтаў прысвячэнняў, што ёсць значна простейшым завданнем, якое можа быць выпаленэ за дапамогою інструментаў з адкрытым кодам.
Выбіранне пакетаў
Для наладкі трэба тры пакеты, кожны з якіх адпавядае за адна конкрэтная задача:
react-native-pdf адмініструе атрыбуты відображэння, выкарыстоўваючы натыўны механізм PDF платформы замест перакладу стораначакоў у адпрацоўваныя на JavaScript зображэння — саме такой натыўны падход дапамагае падтрымваць разумны расход памяці пад час працы з великімі файламі. Ён адпавядае за паказ чыстых стораначакоў, падтрымку зуму, генераванне запускаеў пад час змены стораначака і можлівасць програмнага переходу на певную стораначак.
react-native-blob-util — это залежнасц, ад якой сам react-native-pdf завісіць для доступу да файлаў — ён адпавядае за завантажэнне, кешаванне і чытанне PDF-файлаў, якія паказваюцца. Гэта не дапаможны элемент; гэта неабходнасць, якая ўжо ўключана ў внутршняе функцыонаванне react-native-pdf.
pdf-lib усуне прынцыповую прасоўку, апісаную раней. У зменшэнні на тое, каб адрасаваць ўсё, які лічыцца, ён дазваляе чытаць і маніпулюваць внутраняй структурой PDF безпаслявно: каталагам дакумента, дрэва сторанак, і — што найважлівейша для гэтага варыянта выкарыстоўвання — слоўнікам апісаў, дзе насправды знаходзяцца закладкі ўнутрь PDF, а таксама об’ектамі анотацый звязак, прыўязанымі да адзінаковых сторанак, дзе зберагаюцца як внутранія, так і зовнішняе звязкі. Паколькі react-native-pdf не адображае нічога з гэтага у структураваны чы роўныму спосабе, pdf-lib выкарыстоўваецца для праходжэння праз гэту внутранюю структуру адной раз і стварэння чыстага JSON-прыказу дрэва закладак — заглавле, цэльная сторанка і вярнутыя дзеціныя элементы — плюс скупка разгледзеных канечных пунктаваў звязак, усё гэта незалежна ад платформавыях прыемасцей натыўнага адрасавальніка. Гэты крок выкарыстоўвання должен адбыцца толькі раз.
Прыметка для Expo:
react-native-pdfзавісіць ад натыўных модуляў, таму ён не будзе працаваць у стандартным кліенты Expo Go. Патрэбна спецыяльная версія для разработкі або проста натыўная проектна структура.
Архітэктура
Система складаецца з трох слоёў, кожны з якіх ізольаваны ад внутрашняй працы іншых:
- PDF-пераглядач — стежыць за текущай сторанкай, загальным колькістю сторанак, статусам завантажэння і будзь-якімі статусамі адказоў.
- Панель інструментаў чытальніка — адображае дакладныя вядомасі пра текущую сторанку і дае доступ да панелі закладак.
- Панель закладак — керуе полем для пошуку, дрэва закладак, якое можна розгорнуць (створана на адной з дадзеных, выкарыстоўваючы
pdf-lib), і падае адзіну інформацыю: яку сторанку выбраў корыстувач.
Панель закладак не мае жаднаўства пра тое, як сам PDF атрымлівае свой выгляд, а праглядач PDF не знае, як рэалізуецца пошук закладак. Гэты однонаправлены процес — панель выбірае сторунку, а экран паведамляе праглядачу перейсці туды — і ўскладнюе вядомыя дзеяння, такія як запіс у поле пошуку чыў расширэнне вёскі дрэва, ад калі б гэта могла спрычыніць дорогую переробку самага компонента PDF.
Шаг 1: Структураваць даны закладак
Кожны паветак, з якім вы працуеце, трэбуе трох: заглавья, целевай сторонкі і неабяжнае множыну дзецячых паветакоў — простая рэкурзыўная структура, якая па-прыроднаму паследуе тому, што вяртае крок выкарыстоўвання pdf-lib. Найважлівейшы момант тут — кожны паветак павінен маты стабільны, унікальны ідэнтыфікатор, і гэты ідэнтыфікатор не можа быць проста його пазіцыяй у множыне. Калі корыстувач пачынае вводзіць даннэ пры пошуку або переключае веткі, якія ўвімкнуты чы розключаны, пазіцыя данага паветака ў адрасаванай лісты будзе змінювацца. Якщо вы паслужываецеся індэксам множыны як ідэнтыфікаторам, React трапляецца без можлівасці розразліваць адну строчку ад другой, стан розгортання/згортання прыкладываецца да неправильнага вузла, а FlatList пачынае неправільна перарахоўваць строчкі.
Шаг 2: Пошук без втраты контексту
Паколькі пасоўвач, які адпавядае шукацкаму тэрміну, часта знаходзится на калькі слоёў у структуре дрэва, логіка пошуку павінна пераходзіць па структуре рекурсыўна, а не толькі сканаваць загальныя назвы. Не менш важнае: калі дзеціны ўзлок падходзіць па шукацкаму тэрміну, неабходна таксама залічыць яго абяцель у рэзультатах, нават якшо сама назва абяцелі не падходзіць нічаму. Якшо цього не зрабіць, рэзультат, які знаходзится на глыбокай кальцы, будзе праказаны без жадных пазнак месца, дзе ён насправды знаходзится у дакументе.
Ёжы захаваць швайнасць, пакруціце логіку фільтрацыі ў хук мемаізацыі, так што яна будзе запускацца занова толькі тады, калі змяніцца шукацкі тэкст або даны пасоўвача. Для дрэваў з вялікай колькасцю элементаў таксама дадзіце функцыю затрымкі пад час вводу тексту, каб не перефільтраваць усю структуру пасля кожнага натыку клавішы.
Шаг 3: Разгладзіць толькі видныя узлы
FlatList — гэта правильны інструмент для ціх цыяў з-за праблемы выдатнасці, але ён чакае плоскі масэвы, а не вяроўнаважаную структуру дрэва. Таму вам патрабуецца процес, які праходзіць па дрэве закладак і стварае плоскі масэвы, які складаецца толькі з вузлаў, якія зараз должны быть видны — дзеці вузла ўключаюцца толькі тады, калі гэты вузел зараз розгорнуты. Кожны плоскі элемент таксама должен мець значэнне depth, ўпорам на якое можна будзе визначыць глęбіну його візуальнага відступу.
Гэты крок, можна сказаць, ўсё ж такі ўплывовейшы з точкі зору выкаання ў всім процесе рэалізацыі. Якщо вы спроставіце весь дрэва і проста схаваеце рядкі, якія належаць до згорнутых галузей, FlatList будзе продаваць тыясчы рядкоў, якія ніколі не показуюцца на экране. Спроставляючы толькі тое, што наразе розгорнутае, дрэва з букмаркамі з тыясчамі ентры можа ў кожны момент даўаць FlatList лишо калькі дзесяткаў рядкоў.
Крок 4: Стварэнне панелі букмаркаў
Застосавайце панель як модальную панель, яка знаходзіцца вышэй за праглядач PDF, а не як экран, який заменяе його, і обмежыце ўзраст вышыні панелі прыбліжна 80% дазволенай плошчы экрана, замест таго каб яна захопіла весь экран. Чыгунка так справяецца, што пад панелю залишаецца видны частак PDF, які дапамагае правільнаю оріѐнтацыю, а таксама є месца для чытальнага крану, што не дае вражэння, будто панель — це абсалютна самастоятны экран.
Унутро модальнага вікна патрабуецца: поле пошуку, прыяўнае да логікі з 2-го кроку; FlatList, які адображае рядкі, отрыманыя пасля 3-го кроку, налаштаваны ў значэннях працэсу вікна — initialNumToRender, maxToRenderPerBatch, windowSize і removeClippedSubviews — так, каб адображаліся толькі рядкі, які знаходзяцца поблізу видимай зоны; а таксама стан порожнечы на случай, калі пошук не дае рэзультатаў. Кожны рядок павінен мець два аднародных об’екты для натискання: натыканне на тэла рядка выбірае тую сторунку і закрывае панель, а натыканне на маленькія іконкі розгортання переключае ўсе їхні элементы, так што адкрыванне падгалузі ніколі не спрычыняе випадковага переходу. Кожны компонент рядка трэба загорнуць у memo, каб розгортанне адной падгалузі не вымагала переробкі всіх іншых рядкаў у списку. Крэм таго, калі поле пошуку не порожнее, автаматычна трэба розгорнуць будзь-яю падгалузь.
Шаг 5: Стварэнне экрана чытальні PDF
Саме на гэтым экране відбываецца фактычная візуалізацыя за дапамою компонента Pdf. Што стосуецца функцыі адпаведнасці пасля змены сторанкі, яе трэба викорыстоўваць для стежэння за текущай сторанкай і загальным колькістю сторанак, адображэння вбудованага індыкатора завантажэння бібліятекі пад час чытання дакумента, а таксама для прыўязкі да функцыі адпаведнасці пасля выйскі, каб у разе проблемы на экране ап’явілася чыстая паведамленне „Не удалося ачыніць гэты дакумент“ з можлівасцю пракаты зноў — не дазвольце індыкатору завантажэння круціцца безканечна без альтернатыўы.
Калі вы пераходзите на стороніцу з букмарка, неабяжна ўскладніць номер цяй стороніцы так, каб ён належаў да дыапазону з 1 і адомаганай загальнай колькасці стороніцаў. Гэта заходзіць ад несправныя чы или застарэлай меты — незалежна ад таго, чы яна выйшла з самых дадзэнняў букмарка чы з рашучага внутраняга спылу — якая намагаецца перадаць корыстніка на номер стороніцы, якога проста няма. Таксама варта увімкнуць кэшаванне для PDF-джерела, ўпрымку да таго, каб дакумент, які вялікі час ўжо быў завантажаны, не перазавантажваўся ў кожны раз, калі адкрываецца гэты экран.
Што стосуецца візуальнага стылю, гэта, звычайна, будзе залежаць ад сэрвісу дизайну вашага прылада — але з структурным пункту гляду, для якості викорыстоўвання важліва падтрымка высоты панелі на роўні 80%, наявнасць явным спосабу для ўзначыненняяе, забезпечэнне комфортнага месца для натыкання на кожны ряд (прычаму на іконку расширэння), а таксама стварэнне спакойнага, чыста відзначальнага стану абракцэсу.
Шаг 6: Адаптавація адно, а не празь кожны раз
Этап адаптавання з pdf-lib, працаваны раней, павінен выконвацца адно, за межами цыклу адаптавання — а не ў складніцы, якая перзначае адаптаванне ўсё час, калі корыстнік ведае пошук або розгортае паводзь. Замест таго, каб перакалькуваць даныя знову і знову, зберагайте ў кэшы JSON-файл з паведамленнямі, у стане React залишайце толькі простыя поля (ids, назвы, номеры сторанак), ужоўтрэбаецца утрымлівацца ад зберагання необработанных байтовых дадзеных PDF у стане, а таксама чыставаць усі тымчасовыя ресурсы, калі экран больш не выкананы. Якщо ваш бэкенд можа выконваць этап адаптавання замест вас, гэта зазвычай є болей чыстым падходам — тады мобільныя дапрыемкі павінны прыманць толькі невялікі JSON-пакет.
Шаг 7: Зберагчыць пазіцыю корыстніка
Закрыць панель закладок чы роўнаўчы прыстрой не павінны перзначаць чытальнік на першую сторону. Як мінімум, неабходна захаваць текущую сторону, найняўэлівейшы розгорнуты галузь закладкі і зсув панелі. Храніце гэтыя значэнні на роўні галоўнага экрана чы стану навігацыі, а не внутрь самага компонента панелі закладок — такім чынам яны застануцца нават у разе, калі панель будзе адключена.
Крок 8: Адпаведна раскідацца з адмовамі
Планавайце на рэальныя проблемы, а не толькі на ідеалны ход роботы: URL-адрэсы файлаў, якія не існуюць або выйшлі з чыннасці, дакументы, якія заплямаваны або захіщаны паролем, прыстроі з малым колькам месца для зберагачвання, сеціяны з’ѐднанні, якія перыяюць пад завантажэнням, закладкі, якія вядуць на некоректныя старонкі, або галочкі, якія проста не відкрываюцца. Што б не адбылася, утримайцеся ад таго, каб корыстнік заставаліся з прыстроем для завантажэння, які ніколі не завершае роботу. Якщо дакумент не мае закладак, сказайце пра гэта яшчэ раз — напрыклад, "У этам дакументе няма закладак." Якщо пошук нічога не дае, пакажыце "Закладакі не знайдзены." Чыткая аб’ектнаўка стану "пусто" або "праблема" набагато кращая, чым экран, які проста выглядае так, нібы застряў.
Шаг 9: Апробавайце рэальныя сценарыі праблем
Не пераканвайцеся ў правільнасці сваёй рэалізацыі на аднам толькі зручным PDF-файле. Расшырьце тэставанне на разныя аспекты:
- Дакументы: файлы без жаднае закладок, файлы з сотнямі сторанак, глыбока іерархія закладок, великі вбудованыя зображэння, захаванне паролем, цалёвыя паскоды, внутрашніе і зовнішнія лінкі, а таксама заголовкі з спецыяльнымі символамі
- Навігацыя: переход на закладкі на роўні корэна чыстаць глыбока іерархія закладок, на першую чыстаць апошнюя сторанку, на номер сторанакі за межамі дыапазона, паўтарны ачынэнне панелі пасля яе закрыцьця, пошук у глыбока іерархія закладок, а таксама пошук без рэзультатаў
- Апараты: тэлефон на Android з малай колькасцю памяці, новейшы флагманскі апарат, як iPhone, так і iPad, режымы верхній чыстаць горизонтальны, а таксама переходы між фонам і прэфонам
У гэтым случыку тэставанне на рэальнай апаратнасці мае большое значэнне, чым падчас роботы над большасцю функцый — эмулятор проста не зможа відтворыць тыя навантажэння на памяць і обмежэнні ў прыёмнасці, якія існуюць у рэальным бюджетным прыстрое.
Часта задаваемыя запитанні
Чаму проста не перакладзіць кожную сторонку у формат адпраўкі? Натыўны механізм перакладзу атрымлеўвае на экран толькі тыя данні, якія зараз неабходны, замест таго, каб прымусваць React кераваць окремым компонентам адпраўкі для кожнай з тыяч сторанак.
Чаму вжываць pdf-lib заместо дадзейнай прыкрепленых элементаў, якія вже надае react-native-pdf? Таму што гэтыя вбудованыя дадзеныя не апрацаваны, парадоксальна дзейнуюць на разных платформах (у Windows ўсё адразу не вяртаецца), і не даюць надзейнаг спосабу для адгуквання паходжэння внутраніх лінкаў. pdf-lib безпосередна, за адну процэсуру, парасканавляе структуры апісу PDF і анотацый лінкаў, даючы чыстыя, працоўныя дадзеныя, якімі вы можаеце цалкам кераваць.
Чы можліва пошук усім тэкстам у самым дакументе? Наразе не з абсалютна відкрытымі інструментамі — гэтае можласць наразе прызначана для комерчыях SDK-ў. Тут описаная тэхніка паводзіцца пра пошук па назвах прыкрепленых элементаў, што ёсьць болей вузкія проблема, яку можна цалкам рашыць самастаятельна.
Чы гэтыя веткі ў дрэвах закладак мусяць аўтаматычна розкрывацца? Не — розкрывайце толькі тую ветку, яюякую корыстнік актыўна ачынае. На прыстроях з обмежанай памяцюю цікава абмежыць інтэрфейс так, каб аднойчы за час могла застацца розкрыванай толькі адна ветка на роўні корня.
Чы ўсё гэта гарантуе, што прыкладненне ніколі не зламаецца? Няма такога падходу, які мог бы даты такую гаранцыю для кожнай можлівай комбінацыі дакументаў і прыстроёў. Мета — зменшыць рызык: утрымваць ад некалькага адрасавання, мінімізаваць збераганую інфармацыю, выкарыстоўваць даны толькі аднойчы, вяртуалізаваць спіс закладак і чыста раскрываць кожны варіант абяцаўкі.
Заключныя меркі
Правильна робота з прыткасцю не выключаецца ў выборы аднай бібліятэкі — react-native-pdf адпавядае за атрыбутаванне, pdf-lib супляе надзейныя даныя пра закладкі і звязкі, а практычная стабільнасць залежыць ад таго, як вы керуеце станам, віртуалізацыяй і обработкай адказоў пры викорыстоўванні якой-небудзь з іх.
Практычныя правілы, якія трэба дазвольваць:
- Выконвайте выкарыстоўванне закладак і звязкі аднойчы за дапамогою
pdf-lib, ніколі не як частку процесу атрыбутавання. - Ніколі не атрыбутавайце весь лес закладак заодно — спростаўце і паказвайце толькі раскрытыя часткі.
- Захавайце спіс закладак за дапамогою віртуалізаванага
FlatList. - Полныя байтовыя даны PDF не трэба кансерваціяваць у стане React.
- Пераканайцеся ў правільнасці месца сторонкі пры переходзе на яе.
- Захавайце толькі мінімальны стан, неабходны для вярнення позыцыі чытальніка.