Resolve a module conditionally in react-native - react-native

I want to import ReactNativePropRegistry in my React Native package.
I used to import it from 'react/lib/ReactNativePropRegistry' before React Native 0.38.0 but it has changed to 'react-native/Libraries/Renderer/src/renderers/native/ReactNativePropRegistry' in React Native 0.38.0.
I want my package to be supported on all the React Native versions including 0.38.0 so I did this
if(semver.gte(reactNativeVersion, '0.38.0-rc.0')) {
const ReactNativePropRegistry = require('react-native/Libraries/Renderer/src/renderers/native/ReactNativePropRegistry');
} else {
const ReactNativePropRegistry = require('react/lib/ReactNativePropRegistry');
}
But it seems that the packager tries to resolve the modules statically. So even if reactNativeVersion is less than 0.38.0-rc.0, it tries to resolve the module at this path 'react-native/Libraries/Renderer/src/renderers/native/ReactNativePropRegistry' which causes it to throw an error Unable to resolve module ....
Is there any way get around this?

You cannot do dynamic imports. However, because the React Native packager uses node-haste and both React and React Native use the Haste #providesModule declarations, you may be able to import the module by name without specifying the location:
require('ReactNativePropRegistry');
I haven't tried it for this particular module, but in theory it should work.
It might be good to know that some distant future version of the RN, the packager may drop support for requiring modules by the providesModule name across package boundaries, so this may not be a permanent solution.
However if you're working on a library, eventually you can just deprecate support for versions older than 0.38. Or could you do that already?

Related

How to remove 'Warning: Async Storage has been extracted from react-native core...'?

I've already tried what's recommended in this screenshot
by using this line of code
import AsyncStorage from '../../../node_modules/#react-native-community/async-storage'; in the file where I'm importing async-storage from react-native
but this path is unresolved, i.e. async-storage doesn't exist in this directory. I also tried installing async-storage (even though it's already installed) by running yarn add async-storage, but nothing appeared in the previously mentioned directory
There are two ways you can do this.
Firstly import AsyncStorage correctly. This will remove the warning and fix the problem.
Secondly, suppress the warning. This will just hide the warning but will cause you issues once AsyncStorage has been removed from react-native. I would not do this as the first way actually solves the problem.
Note you can get this warning if you are using a dependency that uses AsyncStorage and still imports it the old way from react-native. Installing AsyncStorage won’t fix the error. You will need to look through your dependencies’ dependencies to find out which one is causing it.
This means actually going through the code of each your dependencies to see if they use AsyncStorage. Searching through your node modules or on the dependency's Github usually is sufficient but it can take some time to find it.
Once you have found out which one is causing it, you should open an issue or create a PR with a fix on the dependency’s repo. At this point suppressing the warning is all you can do until it is fixed.
Install AsyncStorage
Install it using your favourite package manager npm or yarn
Link the dependency
Use the dependency
Installation: choose the method you usually use
npm i #react-native-community/async-storage
or
yarn add #react-native-community/async-storage
Link the dependency (you may not have to do this if you are using 0.60+ as it has Autolinking)
react-native link #react-native-community/async-storage
Then you import it like this, and use it as before.
import AsyncStorage from '#react-native-community/async-storage';
You can see more about it by looking here
Suppress the warning.
Previously you would use YellowBox to suppress warnings, this has now changed to LogBox. The process is similar to that of YellowBox
import { LogBox } from 'react-native';
Then you can add the following
LogBox.ignoreLogs(['Warning: Async Storage has been extracted from react-native core']);
I usually do it in the App.js so it is easy to keep track of which ones I have hidden.
It won't remove the warning from your console, but it will remove any LogBox warnings associated with the error. However, I wouldn’t do this on this occasion as there is a proper fix, which is to install the dependency correctly.
Expo users
Currently Expo still imports AsyncStorage from react-native, due to this you may still experience the warning. I believe it still imports it this way for backwards compatibility reasons. A quick search of the Expo repo shows that there are many instances where it is used as you can see here. In this case your only option would be to suppress the warning. According to the Expo feature requests it is currently in progress, so hopefully it should be added to Expo shortly.
Expo Update
As of June 2020: #react-native-community/async-storage v1.11.0 can be installed in Expo managed apps. Hopefully this will lead to less of these warnings appearing as dependencies transition to the new way of importing async-storage.
Repo update
There is now a new repository for async-storage which can be found here
https://github.com/react-native-async-storage/async-storage
Check out the documentation for installation and linking instructions
https://react-native-async-storage.github.io/async-storage/docs/install/
If the source of the issue is Firebase then a working solution as of version 9.9.2 is to set the default persistence layer used by Firebase to store the authentication session to be AsyncStorage after correctly importing it:
expo install #react-native-async-storage/async-storage
then to add in firebase.js
import AsyncStorage from '#react-native-async-storage/async-storage';
import { initializeAuth, getReactNativePersistence} from 'firebase/auth/react-native';
and then to export { auth } via
const auth = initializeAuth(app, {
persistence: getReactNativePersistence(AsyncStorage)
});
export { auth };
Unlike getAuth(), initializeAuth() gives us control over the persistence layer .
Reference.
For me this issue was with #firebase.
node_modules/#firebase/app/dist/index.rn.cjs.js
following the steps above from Andrew, in vscode I was able to remove the warning.
copy "AsyncStorage"
cmd + shift + f - then paste "AsyncStorage" into search
click three dots under search '...'
right click node_modules folder select 'copy path'
add path to 'files to include' in vscode search
find one example of the import or require statement for the original (incorrect) AsyncStorage, copy that. Paste it into the search, replacing the first search query.
Once all the imports are found install the AsyncStorage correctly for the new version (as mentioned above), also add to pods, then go through and replace all
require('react-native').AsyncStorage; => require('#react-native-community/async-storage').AsyncStorage;
import AsyncStorage from 'react-native'; => import AsyncStorage from '#react-native-community/async-storage';
I did a clean build with xcode, Then all was good to go, no more warning :-)
This seems to be an ongoing issue on Firebase with React Native.
Check out this thread:
https://github.com/firebase/firebase-js-sdk/issues/1847
I have been annoyed by this similar issue and here is my warning message. I simply solved it by:
go to: 'node_modules/react-native/index.js'
simply comment out all the lines that contains 'AsyncStorage'
Then it was working fine for me.
Credits to #Rory for the below steps:
Note: We need to find var reactNative = require('react-native') in node_modules
Note: If you don't want to do the following steps, just navigate to node_modules/#firebase/auth/dist/rn/index.js
cmd + shift + f - then paste var reactNative = require('react-native') into search
click three dots under search '...'
right click node_modules folder select copy path
add path to files to include in vscode search
Then in index.js where we find our search, do the following replacements:
// var reactNative = require('react-native');
var AsyncStorage = require('#react-native-community/async-storage');
// and further below
// var reactNativeLocalPersistence = getReactNativePersistence(reactNative.AsyncStorage);
var reactNativeLocalPersistence = getReactNativePersistence(AsyncStorage);
Refresh and the warning is gone!
if you're using npm
npm install #react-native-async-storage/async-storage
yarn
yarn add #react-native-async-storage/async-storage
YellowBox has been replaced with LogBox. You can use LogBox.ignoreLogs() instead to suppress the warning
In my case firebase using asyn storage from react native . I am using v8 firebase which has no getReactNativePersistence.
So I had this solution which may be helpful.
Keep below code snippet in one file ignoreWarning.js and import in App.js on top of file .
import { LogBox } from "react-native";
const ignoreWarns = [
"AsyncStorage has been extracted from react-native",
];
const warn = console.warn;
console.warn = (...arg) => {
for (const warning of ignoreWarns) {
if (arg[0].startsWith(warning)) {
return;
}
}
warn(...arg);
};
LogBox.ignoreLogs(ignoreWarns);

How to resolve ESLint error unable to resolve path to module 'react-native'

New to react native and trying to setup ESLint in my project. I am getting this specific error:
Unable to resolve path to module 'react-native'. (import/no-unresolved)
I searched on SO and found similar threads, but nothing seems to work. I tried cleaning the npm cache as well.
import { AppRegistry } from 'react-native';
There is a red underline on my index.js file in the project root (using Atom editor) and under the word react in the above code snippet.
As per the react native guide
AppRegistry should be required early in the require sequence to make
sure the JS execution environment is setup before other modules are
required.
If you are struggling with es-lint configuration and guess that it's showing false error then you can add .eslinrc file at the root of the project and configure eslint rule as required. I suggest airbnb standard, this guide show full setup here

Importing react native native module JS not working but importing native module from NativeModules does?

When importing a react-native native module. There is an issue when importing the js from the project for example
import RNModule from 'react-native-module';
However importing RNModule using native modules works:
import { NativeModules } from 'react-native';
const { RNModule } = NativeModules;
Has anyone else experienced this?
I've already tried clearing all the recommended caches as well as rebuilding.
I've tried importing from both the project name react-native-module and the file name rn-module
Example project:
https://github.com/814k31/TestReactNativeNativeModule
(Build and run instructions in README)
This is the import that doesn't work
https://github.com/814k31/TestReactNativeNativeModule/blob/master/RNApp/App.js#L13
But this one does work.
When the button is clicked it will trigger a native Android function
https://github.com/814k31/TestReactNativeNativeModule/blob/master/rn-module/android/src/main/java/com/reactlibrary/RNModuleModule.java#L18
and should make Hello World From RNModule appear on the screen.
Metro bundler doesn't support symlinks...

Unable to resolve module (Expo, React Native)

Building a React Native app with Expo, the Javascript bundle fails after getting the error Unable to resolve "../stores/__fixtures__/matchlist/matchlistSourceFixture" from "src/containers/MatchlistSwipeContainer.tsx", despite the fact that I am 100% sure this file exists and its relative path in this instance is correct – especially as I’m using VSCode and it complains if the path isn’t right and I’m using VSCode’s autocomplete to begin with.
If I move the file into any other directory that is not with __ dunder affixes and update the relative path accordingly, it can find the file perfectly fine.
I’ve checked other similar topics with Unable to resolve module errors, but they all seem to be related to third-party packages, whereas this is a local file.
Import statement:
import { matchlistSourceFixture } from '../stores/__fixtures__/matchlist/matchlistSourceFixture';
Export statement in the file in matchlistSourceFixture.ts:
export const matchlistSourceFixture = {...}
Attached is an image of the error message in the Expo iOS app. The message stating that the file doesn’t even exist (it has a .ts extension by the way) makes me think the relative path isn’t really the issue here anyway.
Versions:
React 16.3.1
Expo 27.0.0
Exp 54.0.0
It seems like __fixtures__ dirs are blacklisted by default in RN: react-native/local-cli/util/Config.js.
See this comment on overriding the default.

Lots of Flow errors in React Native project

I created a React Native project from Expo. Then I wanted to add Flow to it. I noticed in my node_modules/react-native folder there was a .flowconfig so I copied that to the root of my project. After running flow I got some warnings from files in node_modules/exponent so I added an ignore for that whole folder. Afterwards, I still get many errors when running flow. Here are a few:
node_modules/react-native/Libraries/Animated/src/AnimatedImplementation.js:227
227: /* $FlowFixMe */
^^^^^^^^^^^^^^^^ Error suppressing comment. Unused suppression
node_modules/react-native/Libraries/Animated/src/AnimatedImplementation.js:1120
1120: if (__DEV__) {
^^^^^^^ identifier `__DEV__`. Could not resolve name
node_modules/react-native/Libraries/Animated/src/AnimatedImplementation.js:2162
2162: if (__DEV__) {
^^^^^^^ identifier `__DEV__`. Could not resolve name
Expo SDK version: 14.0.0
Flow version: 0.37.0
React Native version: 0.41.2
You can suppress errors in .flowconfig file, in [options] section as follows:
[options]
suppress_type=$FlowFixMe
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-8]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
Then, in [libs] section, you should point so called library definition file, like:
[libs]
./libdefs.js
And in libdefs.js just declare:
declare var __DEV__:string;
These changes should resolve your errors. See:
https://flow.org/en/docs/config/options/#toc-suppress-comment-regex and
https://flow.org/en/docs/libdefs/creation/ for details.
Looks like it might have been an oversight on the flow types for that release version.
All of those errors look fairly harmless though so you could just ignore it. If you absolutely cannot ignore it, update to a later version of React Native that's locked to a different version of Flow? I've had good results personally (no errors) with React Native # 0.42 and Flow # 0.38.
Found this issue which recommended updating the flowconfig to use the latest version from create-react-native-app. Seems to have worked for me.