React native очистить кэш
Things can get. funky in React Native. Here's how to start fresh and reset a React Native app cache.
There are a lot of things in play in a React Native app including:
- NPM/Yarn
- Cocoapods
- Watchman
- Metro bundler
- React Native
- iOS Build
- Android Build
When things start to get weird/unexpected what do you do? Track down how to clear each one of those folders? Just clear one out?
Here's the easiest method.
React Native Clean Project is a CLI plugin that will clear out all the things that could be causing you grief with your React Native app.
First, install the package as a development dependency:
Then you'll want to set up some scripts in your package.json . You've got two options here - interactive or auto.
You can then run those via your command line
Installing react-native-fetch-blob
Add and link the package. No other configuration is needed, since this package is mainly used under the hood.
If you have a non-default project structure, automatic linking might not work. In that case, detailed instructions for manual linking are provided in the project’s wiki.
Qisheng-Lu commented Jun 22, 2020
Thank you! deleting node_modules & npm install & npm start -- --reset-cache works fine.
sebaxf commented Jun 9, 2020
Thank me later or not at all. Either way it's all good:
npm start -- --reset-cache
License
This project is licensed under the MIT License - see the LICENSE.md file for details
the-habu commented Mar 30, 2020 •
Even simpler solution:
npm uninstall -g react-native-cli
rm -rf ~/Projects/react-native-*
echo "127.0.0.1 facebook.github.io" > /etc/hostsLeave RN in the trash where it belongs. You'll thank me.
It's dangerous to go alone, take this: 🖕
Authors
See also the list of contributors who participated in this project.
useEffect
Внутри компонентов для получения данных можно задействовать хук useEffect , после чего сохранять эти данные локально (внутри компонента) с помощью useState :
При передаче пустого массива в качестве второго параметра (строка 11) хук useEffect будет выполнен после встраивания компонента в DOM. При новом отображении компонента повторно он выполняться уже не будет. Назовем этот хук “одноразовым”.
В связи с применением useEffect таким способом следует упомянуть о том, что при наличии нескольких экземпляров компонента в DOM все они будут получать данные по отдельности (при встраивании).
В этой технике нет ничего плохого. Более того, иногда она приходится как нельзя кстати. Но в ряде случаев требуется единожды получить данные и повторно их использовать во всех других экземплярах посредством кэширования. С этой целью можно обратиться к другим техникам.
Мемоизация — это мудреный термин для обозначения очень простой техники. Суть ее в том, что вы создаете функцию, которая при каждом вызове сохраняет результаты в кэше, прежде чем их вернуть.
При первом вызове такой мемоизованной функции результаты вычисляются (или получаются — все зависит от выполняемых операций внутри тела функции). Прежде чем вернуть результаты, вы сохраняете их в кэше в ключе, который создается с входными параметрами:
Написание такого шаблонного кода вскоре может стать трудоемким процессом, поэтому такие известные библиотеки, как Lodash и Underscore, предоставляют вспомогательные функции, упрощая создание мемоизованных:
Direct execution
For complete control (including using command-line arguments to non-interactively fine-tune what state is cleaned):
Or add it as a script to your package.json
Carlos767 commented Jun 4, 2020
disrae commented May 19, 2020
Hmmm, not working for me, and I'm not using npm start, but I tried clearing the npm cache and running the watchmen command.
Why Auto?
Auto mode is going to use the CLI defaults to get the app back to a "freshly-cloned, never-started repo".
Benefit: Run it and forget it. No decisions or monitoring required.
Drawback: Slower initial rebuild time because you have to rebuild every cache.
utkalpatel-dev commented Jun 30, 2020
I had so many issues on clearing the cache. Turns out that the metro bundler and haste map has changed their directory structure. 👎
This is the script I use to clean the cache:
watchman watch-del-all && rm package-lock.json && rm -rf node_modules && rm -rf $TMPDIR/metro-* && rm -rf $TMPDIR/haste-map-* && npm installThis has costed us DAYS, hope this helps someone :)
you save my day bro.. I tired every thing but nothing worked and finally your solution rocks
Компонент People
Отображая данные из API, мы передаем их в компонент с именем PeopleRenderer . Выглядит это следующим образом:
Имея в виду эту вводную информацию, рассмотрим первую технику.
sakillin commented Feb 19, 2020
I just ran into an issue that required figuring out how to purge everything related to a React Native build and I feel all the pain here. For sanity, I finally went and Dockerized the bundler and pointed the native app at the container just to make sure I wasn't crazy. That helped, since I could at least know that my application was working in theory.
It is very frustrating to have to go to 6 different places to get this reset.
- rm -rf means to recursively remove all files/folders at the following path
- $TMPDIR is the environment variable for your systems temporary directory, it isn't the same on every platform
- $TMPDIR/metro-* means every file/folder that matches with the * wildcard (so metro-foo as well as metro-bar)
- The && means "run this command as well
So the whole command means to recursively purge any files that start with "metro-" or "haste-map-" from your system's temporary directory.
Installing react-native-cached-image
When react-native-fetch-blob is installed, adding react-native-cached-image is simply a matter of adding it to your project.
Installing
yarn add -D react-native-clean-project
Contributing
Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.
wikramdas commented Apr 23, 2020
Hey guys hope you all are doing good.
I have a problem in react native app I want to add clear cache option in react native app for users to clear app cache when they want to clear basically my app is wallpapers app.
So kindly help me if it is possible.
Thanks
Other Tips
You can also reset the Metro bundler cache when starting with react-native start --reset-cache
Running
React-Native CLI plugin
This module is automatically detected as a plugin by the standard react-native command, adding new sub-commands:
- react-native clean-project-auto - fully automated project state clean: like a freshly-cloned, never-started repo
- react-native clean-project - interactive project state clean: choose types of react-native state to clean
Support
This library does not support windows. PR's are welcome.
akinolu52 commented Jun 6, 2020
@Carlos767
close your terminal, delete your project node_modules then
npm i && npm start -- --reset-cache
tomlobato commented Jan 12, 2020
Nice, tks @jotapepinheiro !
Why the 'react-native link' is needed here?
Content
This is a combination of the commands suggested in the React Native documentation plus others.
State Type | Command | In clean-project-auto ? | Optional? | Default? | Option Flag |
---|---|---|---|---|---|
React-native cache | rm -rf $TMPDIR/react-* | Yes | No | true | |
Metro bundler cache | rm -rf $TMPDIR/metro-* | Yes | No | true | |
Watchman cache | watchman watch-del-all | Yes | No | true | |
NPM modules | rm -rf node_modules | Yes | Yes | true | --keep-node-modules |
Yarn cache | yarn cache clean | Yes | Yes | true | --keep-node-modules |
Yarn packages | yarn install | No | Yes | true | --keep-node-modules |
NPM cache | npm cache verify | Yes | Yes | true | --keep-node-modules |
NPM Install | npm ci | Yes | Yes | true | --keep-node-modules |
iOS build folder | rm -rf ios/build | Yes | Yes | false | --remove-iOS-build |
iOS pods folder | rm -rf ios/Pods | Yes | Yes | false | --remove-iOS-pods |
system iOS pods cache | pod cache clean --all | Yes | Yes | true | --keep-system-iOS-pods-cache |
user iOS pods cache | rm -rf ~/.cocoapods | Yes | Yes | true | --keep-user-iOS-pods-cache |
Android build folder | rm -rf android/build | Yes | Yes | false | --remove-android-build |
Android clean project | (cd android && ./gradlew clean) | Yes | Yes | false | --clean-android-project |
Brew package | brew update && brew upgrade | No | Yes | true | --keep-brew |
Pod packages | pod update | No | Yes | true | --keep-pods |
Example: ./node_modules/.bin/react-native-clean-project --remove-iOS-build
Why is this necessary? Why does this happen?
Like I said before, there are a lot of moving parts in a React Native app.
We're working with a multiple ecosystems (NPM, Cocoapods), multiple platforms (iOS, Android, Web), and multiple tools (React Native, Metro, Homebrew). 💩 happens and sometimes we need to clean it up.
React Native School
Want to further level up as a React Native developer? Join React Native School! You'll get access to all of our courses and our private Slack community.
Join our email list and get free access to our crash course on building React Native apps.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
RN < 0.50 - watchman watch-del-all && rm -rf $TMPDIR/react-* && rm -rf node_modules/ && npm cache clean && npm install && npm start -- --reset-cache |
RN >= 0.50 - watchman watch-del-all && rm -rf $TMPDIR/react-native-packager-cache-* && rm -rf $TMPDIR/metro-bundler-cache-* && rm -rf node_modules/ && npm cache clean && npm install && npm start -- --reset-cache |
RN >= 0.63 - watchman watch-del-all && rm -rf node_modules && npm install && rm -rf /tmp/metro-* && npm run start --reset-cache |
npm >= 5 - watchman watch-del-all && rm -rf $TMPDIR/react-* && rm -rf node_modules/ && npm cache verify && npm install && npm start -- --reset-cache |
Windows - del %appdata%\Temp\react-native-* & cd android & gradlew clean & cd .. & del node_modules/ & npm cache clean --force & npm install & npm start -- --reset-cache |
Jp3rd commented May 28, 2020
- rm -rf means to recursively remove all files/folders at the following path
- $TMPDIR is the environment variable for your systems temporary directory, it isn't the same on every platform
- $TMPDIR/metro-* means every file/folder that matches with the * wildcard (so metro-foo as well as metro-bar)
- The && means "run this command as well
This worked for me, the metro cache file names have changed. I am using RN 0.59
Why Interactive?
Interactive is going to let you choose what you clear from the cache. If you suspect it's one thing, or it's only affecting one platform, you can just focus there.
Benefit: Faster build times because you don't need to reinstall and rebuild all the caches.
Drawback: You have to monitor it and make decisions.
Using react-native-cached-image
When both packages are successfully installed, you can import CachedImage and replace any instances of Image or ImageBackground that you want cached.
In my example app, I set up a FlatList to show the images. The renderItem implementation can thus be changed.
When this was done, I repeated the previous experiment and opened and closed the example app five times. This was the result.
As you can see, the images are downloaded once and subsequently fetched from cache. This has the added benefit of not having to deal with slow and unpredictable networks, thus giving you app faster response times and better offline support.
Cleans your React Native project by purging caches and modules, and reinstalling them again.
safarishi commented Feb 10, 2020
I had so many issues on clearing the cache. Turns out that the metro bundler and haste map has changed their directory structure. 👎
This is the script I use to clean the cache:
watchman watch-del-all && rm package-lock.json && rm -rf node_modules && rm -rf $TMPDIR/metro-* && rm -rf $TMPDIR/haste-map-* && npm installThis has costed us DAYS, hope this helps someone :)
What's the meaning for the follow command "rm -rf $TMPDIR/metro-* && rm -rf $TMPDIR/haste-map-*" actually mean?
Мемоизация для получения данных
Данная техника подходит для получения данных. Мы создаем функцию getData , возвращающую обещание Promise , разрешение которого происходит по окончании fetch-запроса. Мы сохраняем этот Promise :
Обратите внимание, что в данном примере мы не проводим обработку ошибок. Эта тема заслуживает отдельной статьи, особенно в связи с мемоизацией (поскольку отклоненное обещание Promise тоже бы сохранилось, что чревато проблемами).
Теперь заменим хук useEffect на другой, который выглядит следующим образом:
Поскольку результат getData сохраняется, то при встраивании все компоненты получат одинаковые данные:
Стоит также отметить, что при открытии страницы memoize.tsx (до добавления первого экземпляра компонента) данные уже предварительно получаются. Дело в том, что мы определили функцию getData в отдельном расположенном в верхней части страницы файле, при загрузке которого создается Promise .
Можно аннулировать (очистить) кэш мемоизованной функции, присвоив ее свойству cache нового Cache .
В качестве альтернативного варианта можно очистить существующий кэш (это экземпляр Map ).
Однако данная функциональность характерна лишь для Lodash. Другие же библиотеки требуют иных решений. Ниже представлен наглядный пример очистки кэша в действии.
React Context — еще один известный и подробно изученный инструмент (в отношении которого однако часто происходит недопонимание). В связи с этим в очередной раз напоминаю, что он не заменяет такие инструменты, как Redux, поскольку не является средством управления состоянием.
Итак, что такое Context? Это механизм для внедрения данных в дерево компонентов. Если у вас есть некие данные, то их можно сохранить, к примеру, с помощью хука useState , внутри компонента, находящегося на более высоком уровне иерархии. Затем с помощью Provider Context внедрить эти данные в дерево, что позволит считывать (использовать) их в любом нижестоящем компоненте.
Для большей ясности приведем пример. Сначала создаем новый контекст.
После этого обертываем компонент, отображающий компоненты People , в Provider Context.
В 12 строке у нас есть возможность отобразить любой элемент. В определенный момент, опускаясь вниз по дереву, отобразим компонент(ы) People .
Можно применить значение из Provider с помощью хука useContext , получая следующий результат.
Обратите внимание на одно важное здесь отличие! На последнем этапе анимации мы нажимаем кнопку “Set new seed”. При этом повторно получаются данные, хранящиеся в Provider Context. По завершении этого (спустя 750 мс) полученные данные становятся новым значением Provider , и компоненты People отображаются еще раз. Как видите, все они пользуются одними и теми же общими данными.
Эта техника значительно отличается от ранее рассмотренного примера мемоизации, в котором каждый компонент хранил собственную копию мемоизованных данных с помощью useState . В этом же случае, задействуя контекст, они не хранят копии, а оперируют только ссылками на один и тот же объект. Вот почему все компоненты обновляются одинаковыми данными при обновлении значения в Provider .
В последнем, но не маловажном разделе, проведем беглый обзор useMemo . От предыдущих техник этот хук отличается тем, что он является лишь формой кэширования на локальном уровне: внутри одного экземпляра компонента. useMemo не предназначен для совместного использования данных несколькими компонентами — по крайней мере, не без обходных решений в виде пробрасывания (prop-drilling) пропсов или внедрения зависимостей (например, React Context).
useMemo — это инструмент оптимизации. Он позволяет избежать пересчета значения при каждом повторном отображении компонента. Нет лучшего объяснения, чем сама документация, но рассмотрим пример.
- getRnd (строка 2): функция, возвращающая случайное число в диапазоне 0–10000.
- age (строка 4): с помощью useState сохраняет число, обозначающее возраст.
- randomNumber (строка 5): сохраняет случайное число посредством useState .
И наконец, в строке 7 применяется useMemo . Мы запоминаем результат вызова функции и сохраняем его в переменной pow . Функция возвращает значение суммы age , возведенной во вторую степень, и случайного числа. Поскольку она зависит от переменной age , мы передаем эту переменную в аргумент зависимости вызова useMemo .
Функция выполняется только в случае изменения значения age . Если компонент отображается повторно, а значение age не изменилось, useMemo просто вернет мемоизованный результат.
В этом примере вычисление pow не представляет большой сложности, но не трудно представить себе все преимущества данного подхода в случае с более громоздкой функцией и при необходимости частого повторного отображения компонента.
Две последние анимации показывают, что происходит. Сначала мы обновляем randomNumber , не затрагивая значение age , вследствие чего наблюдаем useMemo в действии (значение pow не меняется при повторном отображении компонента). При каждом нажатии на кнопку компонент заново отображается.
Однако изменение значения age повлечет за собой изменение pow , поскольку вызов useMemo зависит от значения age .
andresprogra commented Jan 15, 2020
watchman watch-del-all && rm -rf node_modules/ && npm cache clean --force&& npm install && npm start -- --reset-cache
vnshah commented Apr 19, 2020
Thank me later or not at all. Either way it's all good:
npm start -- --reset-cache
Worked like a charm! Thanks man.
shardick commented Apr 11, 2020 •
Works on Windows 10 & react native >= 0.60
Заключение
Для кэширования данных в JavaScript существуют разные техники и вспомогательные средства. В данной статье мы прошлись по самым верхам, тем не менее надеюсь, что полученные знания помогут вам в дальнейшем продвижении в мире разработки.
С полным вариантом кода, представленного в статье, можно ознакомиться в репозитории на GitLab.
I can still recall the moment where I realised something was terribly wrong.
I was on the verge of publishing my first app. I had gone over everything and I felt I had my bases covered.
It was then I suddenly wondered how much data my app was actually consuming. Not that I was concerned. After all, it couldn’t be much. Some news headline images and some item thumbnails surely wouldn’t make a dent.
It turned out I was wrong. My seemingly innocent little app had already devoured hundreds of megabytes of data and it didn’t take long to find the culprit. The images were downloaded every time the app was launched, none of them were cached.
To give you an idea of what caching images can mean for your applications, I built an experiment that fetches ten image from Unsplash without any caching enabled. The average file size is 10 megabytes.
This is the result of opening and closing the app five times.
The app downloads the images every time it launches, which is very much undesired and poor design.
Not only does this result in exponential data usage, which is an unpleasant surprise for your customers, it also makes your apps reliant on network connection every time external images are shown. This can either result in long loading times or no images at all.
To provide our apps with minimal data usage, faster reponse time and improved offline capabilities, let us take a look at how we can cache external images.
When questing for functionality, it is worthwhile to see what React Native provides out-of-the-box before resorting to external packages.
Regarding image caching, however, it is a bit wanting. For a long time, React Native did not offer any image caching capabilities at all. They only recently added a Cache property to their image components, giving some control over the cache layer.
This is a quick example, as seen in the docs.
The big caveat here is that, at the time of writing, cache-control is supported only for iOS. On top of that, it does not always work as it should, providing a less-than-optimal solution.
A better alternative, in my opinion, is a package called react-native-cached-image by Kfir Golan.
React-native-cached-image provides a CachedImage component that serves as a drop-in replacement for Image and ImageBackground. Should the need arise, you can also use ImageCacheManager for more fine-grained cache control.
Before we can use this package, however, we must first add react-native-fetch-blob on which react-native-cached-image relies for its file system access.
thatsatul commented Aug 30, 2020
Getting same error.
error: bundling failed: Error: Unable to resolve module @babel/runtime/helpers/interopRequireDefault from /index.android.js : Module @babel/runtime/helpers/interopRequireDefault does not exist in the Haste module map
Yarn add @babel/runtime not working.
react-native start --reset-cache not working.
Uninstalling watchman not working.
Below command is also not working for me.
watchman watch-del-all && rm -rf $TMPDIR/react-native-packager-cache-* && rm -rf $TMPDIR/react-* && rm -rf $TMPDIR/metro-* && rm -rf node_modules/ && yarn cache clean --force && yarn install && react-native start --reset-cache
React Native Environment Info:
System:
OS: macOS 10.14.6
CPU: (8) x64 Intel(R) Core(TM) i5-8257U CPU @ 1.40GHz
Memory: 82.13 MB / 8.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 10.16.3 - /usr/local/bin/node
Yarn: 1.19.1 - /usr/local/bin/yarn
npm: 6.9.0 - /usr/local/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
SDKs:
iOS SDK:
Platforms: iOS 13.1, DriverKit 19.0, macOS 10.15, tvOS 13.0, watchOS 6.0
Android SDK:
API Levels: 28, 29
Build Tools: 28.0.3, 29.0.2
System Images: android-28 | Google APIs Intel x86 Atom, android-28 | Google Play Intel x86 Atom, android-29 | Google APIs Intel x86 Atom
IDEs:
Android Studio: 3.5 AI-191.8026.42.35.5900203
Xcode: 11.1/11A1027 - /usr/bin/xcodebuild
npmPackages:
react: 16.8.6 => 16.8.6
react-native: 0.59.9 => 0.59.9
npmGlobalPackages:
react-native-cli: 2.0.1
If there are some other solutions, please suggest. Totally stuck at this problem for 2 days.
Получение данных в React — это один процесс, а вот их хранение и кэширование — совсем другой. Возможности кажутся безграничными, а отличия зачастую настолько тонкие, что выбрать правильную технику становится не так уж и просто.
В статье мы рассмотрим различные техники, обращая внимание на все их нюансы и неуловимые различия. Что выбрать: useMemo или мемоизацию, хранение данных с помощью useState или контекста? Изучив материал, вы сможете принимать осознанные решения относительно кэширования данных и будете владеть подробной информацией по данной теме. А еще вас ждет много GIF-анимации.
Перед тем, как углубиться в код, быстро просмотрим данные, которые нам предстоит получать в большинстве компонентов. Файл, выступающий в роли API, выглядит следующим образом:
Этот код выполняется при осуществлении запроса к пути проекта /api/people . Как видно, мы возвращаем объект с двумя свойствами:
- randomNumber : произвольное число в диапазоне 0–10000.
- people : статический массив с тремя вымышленными именами.
Свойство randomNumber поможет наглядно продемонстрировать, происходит ли отображение кэшированных данных во фронтенде. По мере углубления в тему вы поймете, о чем идет речь.
Обратите внимание, что мы имитируем небольшую сетевую задержку, используя setTimeout .
Читайте также: