How to set up environment variables in react native - react-native

I'm making a react native app that makes a request to my server hosted on heroku.
Should I be hiding the URL of my server and if so how can I add an environment variable to a react native project?
I have made a .env file and then have done this:
console.log(process.env.URL)
Which is returning undefined - I am also using expo if that makes a difference.

If you use Expo, there is an easy way to create environment variables.
In your app.json file
{
"expo": {
"extra": {
"URL": "https://..."
}
}
}
After that, you will need to install the expo-constant package.
expo install expo-constants
And, to get the info in your app:
import Constants from "expo-constants";
console.log(Constants.manifest.extra.URL);

One library that I like to use that works for bare react native and expo is react-native-dotenv
Install it npm i react-native-dotenv
Add a .env file with your variables
MY_ENV_VARIABLE=SECRET_PASSWORD
Add the babel plugin to .babelrc file.
{
"plugins": [
["module:react-native-dotenv"]
]
}
Import and use it
import { MY_ENV_VARIABLE } from "react-native-dotenv";
function doSomething() {
console.log(MY_ENV_VARIABLE);
}

Related

How to mock NativeModules in react-native project by js side?

I am working on runnning my react-native app with expo, the problem I am facing is to mock the NativeModules exported by "react-native", my current solution is using babel-plugin-module-resolver plugin to redirect the "react-native" module to my "react-native-proxy" module, which exports a proxy object that expanding NativeModules.
Everything goes well untill I want to use expo-file-system to mock our native FileSystem api, expo-file-system is an es module, an error look like caused by module mixed use occured. I tried import * as FileSystem from 'expo-file-system'; in babe.config.js, "react-native-proxy" module, metro.config.js, both throwed an error.
How could I require an es module in babel.config.js or babel-plugin?
Or any idea of achieving the target mentioned above?
Thanks.
Solved by myself.
As I know that, the NativeModules object exported from "react-native" is created in Libraries/BatchedBridge/NativeModules.js, so I change my mock target to this file. I create a file name "NativeModulesProxy.js" which content copied from "Libraries/BatchedBridge/NativeModules.js", then use babel-plugin-module-resolver plugin to redirect the src file to this one.
// babel.config.js
const resolvePath = require('babel-plugin-module-resolver').resolvePath;
const path = require('path');
...
plugins: [
[
'module-resolver',
{
resolvePath(sourcePath, currentFile, opts) {
if (sourcePath.includes('NativeModules')) {
const sourceAbsolutePath = path.resolve(path.dirname(currentFile), sourcePath);
if (sourceAbsolutePath.endsWith('node_modules/react-native/Libraries/BatchedBridge/NativeModules')) {
return path.resolve(__dirname, 'NativeModulesProxy');
}
}
return resolvePath(sourcePath, currentFile, opts);
}
}
]
],
...
NativeModules object is a quote of global.nativeModuleProxy, base on this, I could create my own proxy object like "global.myNativeModuleProxy" which combines global.nativeModuleProxy and my mock native modules.

Use optimized es6 build of MobX for React Native in Metro config

I'm trying to use the optimized, es6 build of Mobx, as per the documentation:
Tip: the main entry point of the MobX 5 package ships with ES5 code for backward compatibility with all build tools. But since MobX 5 runs only on modern browsers anyway, consider using the faster and smaller ES6 build: lib/mobx.es6.js. For example by setting up a webpack alias: resolve: { alias: { mobx: __dirname + "/node_modules/mobx/lib/mobx.es6.js" }}
https://mobx.js.org/README.html#browser-support
This allows me to import mobx and get the mobx.es6.js build:
import mobx from 'mobx' // Yay, es6 build!!!
This works great for Webpack-based projects, such as Electron ones, where I already have it working.
For React Native, I can specify extraNodeModules in metro.config.js like so:
module.exports = {
resolver: {
extraNodeModules: {
"mobx": path.resolve(__dirname, 'node_modules/mobx/lib/mobx.es6.js'),
},
},
};
...except that doesn't work, I presume, because the mobx dependency resolves fine on its own, and so this configuration option is never checked.
I can use a separate alias for mobx, such as mobx-es6 but that's not ideal, to put it nicely:
module.exports = {
resolver: {
extraNodeModules: {
// Nooo I don't want to update a bazillion source files!.
"mobx-es6": path.resolve(__dirname, 'node_modules/mobx/lib/mobx.es6.js'),
},
},
};
Is there some other way to configure Metro so that I can override the mobx import like I can with Webpack?
I'm using RN 0.60.0.
The solution is to add a browser section to package.json:
"name": "My React Native Project",
"version": "0.0.1",
"browser": {
"mobx": "mobx/lib/mobx.es6.js"
},
This is undocumented, AFAICT, but there are hints here:
resolverMainFields
Type: Array<string>
Specify the fields in package.json files that will be used by the module resolver to do redirections when requiring certain packages. For example, using ['browser', 'main'] will use the browser field if it exists and will default to main if it doesn't.
https://facebook.github.io/metro/docs/configuration#resolvermainfields
import mobx from 'mobx' // Yay, es6 build!!!

Map object in React Native

I am new in React Native. Right now, I am studying Props and State. I wanted to try the FlatList Component in this doc https://facebook.github.io/react-native/docs/flatlist. However, I am getting this error.
You're using typed JavaScript known as Type script.
If you want to use TypeScript (I highly encourage it, then you can do so by following below tutorial):
Migrating to TypeScript:
https://facebook.github.io/react-native/blog/2018/05/07/using-typescript-with-react-native
To just get rid of the error!
state = {selected : (new Map())};
TypeScript Migration Continued...
Adding TypeScript
The next step is to add TypeScript to your project. The following commands will:
add TypeScript to your project
add React Native TypeScript Transformer to your project
initialize an empty TypeScript config file, which we'll configure next
add an empty React Native TypeScript Transformer config file, which we'll - configure next
adds typings for React and React Native
Okay, let's go ahead and run these.
yarn add --dev typescript
yarn add --dev react-native-typescript-transformer
yarn tsc --init --pretty --jsx react
touch rn-cli.config.js
yarn add --dev #types/react #types/react-native
The tsconfig.json file contains all the settings for the TypeScript compiler. The defaults created by the command above are mostly fine, but open the file and uncomment the following line:
{
/* Search the config file for the following line and uncomment it. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
}
The rn-cli.config.js contains the settings for the React Native TypeScript Transformer. Open it and add the following:
module.exports = {
getTransformModulePath() {
return require.resolve('react-native-typescript-transformer');
},
getSourceExts() {
return ['ts', 'tsx'];
},
};
Migrating to TypeScript
Rename the generated App.js and __tests_/App.js files to App.tsx. index.js needs to use the .js extension. All new files should use the .tsx extension (or .ts if the file doesn't contain any JSX).
If you tried to run the app now, you'd get an error like object prototype may only be an object or null. This is caused by a failure to import the default export from React as well as a named export on the same line. Open App.tsx and modify the import at the top of the file:
-import React, { Component } from 'react';
+import React from 'react'
+import { Component } from 'react';
Some of this has to do with differences in how Babel and TypeScript interoperate with CommonJS modules. In the future, the two will stabilize on the same behaviour.
At this point, you should be able to run the React Native app.

Cannot find entry file index.js with Expo XDE

When I load my react-native app in Expo I get the error: "Cannot find entry file index.js in any of the roots."
I am adding onto an existing React Web App, and have index.ios.js at the root level. Everything works fine locally, in simulator and through Xcode on my phone hardwired. I've converted my app with exp convert and integrated all info into exp.json.
All info for the ios app is contained in a folder called "ios".
Has anyone run into this or have any thoughts on how to get unstuck?
check you package.json and rename index.js to your entry file.
//...
},
"main": "index.js"
}
If you are using Expo, you need to go to your project folder and find the below file:
\node_modules\expo\AppEntry.js
import { KeepAwake, registerRootComponent } from 'expo';
import App from '../../App';
if (__DEV__) {
KeepAwake.activate();
}
registerRootComponent(App);
and here just replace the App to Custom_Component_Name in the second line of import.
You can find the entry file by looking in the package.json file. In package.json you will find
{
"main": "node_modules/expo/AppEntry.js"
}
AppEntry.json is the entry file by default in expo projects.

React Native: Unable to resolve module fs

Unable to resolve module fs from /...mypath
I got this error when trying to import a node module into my react-native app.
The module used 'fs' in this way:
var fs = require('fs');
var list = JSON.parse(fs.readFileSync(__dirname + '/list.json', 'utf8'));
I ended up using 'rn-nodeify' to include fs into React Native. You can use most of the node core modules this method. Install it with npm:
npm install rn-nodeify
Then in package.json file, add the following line in "scripts" to specify which modules you want to include in your RN project. For example, I used fs, crypto and https, and the line goes
"postinstall": "node_modules/.bin/rn-nodeify --install crypto,fs,https --hack"
React Native applications do not run in the Node.js environment (it is only used by the packager to actually serve and compile your application bundle).
Since your app is running inside JS VM on either iPhone or Android, the only way to access filesystem is to use react-native-fs or any other 3rd party module that utilises bridge connection to talk to the platform specific native APIs.
it took me a while to find the issue, I'm sharing it as it might be useful for future reference (using react native with Expo):
One of my coworkers accidentally imported in one of our react components app.config.js in the project root to read some configuration rather than using expo-constants.
it was causing it to read the .env file from the react native wrapper that obviously doesn't have the fs lib.. this is the first line of our app.config.js:
import 'dotenv/config';
the correct way for reading settings inside app.config is:
import Constants from 'expo-constants';
const appConfig = Constants.manifest;
Install react-native-fs (follow the instructions at de link), so weather the error persist, enter at the directory ('./node_modules/tfjs-image-recognition-base/build/commonjs/env/) search by the file: (creatFileSystem.js) and edit:
fs = require('fs')
to:
fs = require('react-native-fs')
I don't know if this is recommended way, but was the only that worked for me.
If you want to import a json list just call it direct.
Example:
import subscriptionData from './assets/dataSource/subscriptionData.json';
or
var subscriptionData = require('./assets/dataSource/subscriptionData.json');
You don't need to convert it, and you can use to import your data or the way you want.
function installJson() {
console.log("Iniciando Importação");
subscriptionData.forEach(item => {
firestore().collection('subscription').add(item);
});
}
subscriptionData.json
[{
"code": 325,
"name": "bla bla bla"
},
{
"code": 356,
"name": "ble ble ble"
}]
Instead of:
const fs = require('fs');
Try:
const fs = require('react-native-fs');
worked in my case.