How to run code on App Start-up in React-Native - react-native

So I have a react-native application and want to run some code on app start-up;
The application has background task handlers(android) which (to the best of my knowledge) does not mount any views so initializing stuff in the root constructor or componentDidMount may not work.
I want to add certain database listeners to my application which get triggered even while the app is being run in background.
Any help on the same would be highly appreciated.
Thanks regards.
Amol.

In functional components, you want to use the useEffect() method with an empty dependency array:
useEffect(() => {
// this code will run once
}, [])
When an empty dependency array ([]) is used, the useEffect() callback is called only once, right after the component renders for the first time.
Use like this:
import React, { useEffect } from 'react'
export default function App () {
useEffect(() => {
// this code will run once
}, [])
// ...
}

React-Native has a function super() which is same as constructor() that will work when your application get started. For example if you write a alert message on your super() function('When a user open your app, an alert message will be display'. You are able to get data using super() function when your app is opened)
super(){
alert('app started')
}

Related

How can I perform a function when the page shows or the app launches in React Native

In React Native, how can I perform a function when the page shows or any component shows, this really confuses me a lot, I can't find the solution in the Documents, and I use functions to declare the components.
Use a class component and and call your function in the componentDidMount lifecycle method
use can also use hook instead of componentDidMount, I personally find code more readable with hooks
import React, { useEffect } from 'react'
const Component = () => {
useEffect(() => {
//do anything here
}, [])
return(
//JSX
)
}

How to make api calls when component is loaded multiple times

I need to fetch products each time a user navigates the products screen of a react native app being built with expo. I found out that the component lifecycle hook : componentDidMount is called just once. This is an issue because if the products are updated on the backend / API, if the componentDidMount is not called again when the user visits the product page again, they won't see latest products which defeats the purpose of the app. How may i approach this ?
Thanks
Use componentDidUpdate() method. This will execute automatically before render() method gets triggered.
Please read this to know about the life cycle of react-native.
Call a function inside componentDidUpdate() like this
componentDidMount()
{
this.loadInitialState();
}
and then do your API call and set state in loadInitialState() function. Hope this will work
Hope it helps .feel free for doubts.
You can add a navigation listener: Subscribe to updates to navigation lifecycle
this.props.navigation.addListener(
'didFocus',
() => {
this.getData()
}
)
use WebSocket for realtime application

Store data while app is running [React Native]

I'm trying to set a variable in my app which is active only while the app is running and will be destroyed when the app is exited. The concept is something like session in web browser where the session will be destroyed only when the browser is closed.
For some reason I cannot use state as it will get renewed when there is dispatch action triggered. I had a thought of using AsyncStorage.setItem() but it doesn't work in my situation too as it is storing the variable in the device. Else there is a way to do removeItem when the app is exiting without triggering any button.
As pointed out above in a comment, it looks like the AppState API is your friend here. Untested example code:
class AppStateExample extends Component {
componentDidMount() {
this.temp = "something"
AppState.addEventListener('change', this.handleAppStateChange);
}
handleAppStateChange = (nextAppState) => {
if (nextAppState.match(/inactive|background/)) {
this.temp = null
}
};
}
Use redux as this does have the same behaviour what you want. you can store in a store and it gets destroyed when app is exited.

How To Use both 'adjustPan' and 'adjustResize' for 'windowSoftInputMode' in React Native Android app

How can I use both 'adjustPan' and 'adjustResize' in AndroidManifest.xml react native app.
Use Case
My navigation is made upon ReactNavigation with StackNavigator and TabNavigator. I have a text box where the user can type any data. While performing this, the tab bar is displaying on the top of Keyboard. In order to block this i used 'adjustPan' and it worked fine.
On another screen, I have a registration with multiple text boxes. Here I cant scroll the entire screen unless and clicking 'tick' on the keyboard or manually click system back button. To solve this issue I found 'KeyboardAvoidingView' which is working fine. but to activate this need to change 'windowSoftInputMode' to 'adjustResize'.
In documentation, found that these two have entirely different property and I can't both together. could someone help me on this?
References:https://medium.freecodecamp.org/how-to-make-your-react-native-app-respond-gracefully-when-the-keyboard-pops-up-7442c1535580
I found an npm package called react-native-android-keyboard-adjust, which allows us to switch the windowSoftInputMode on demand, this should be able to cater for your use case. However, the library seems to be not actively maintained and the installation documentation is a little bit out of date but for the most part, you can follow the instructions given by the README.md.
For the Update MainActivity.java in your project part, the recent versions of React Native should be able to auto-link the dependencies and there is no need to do this modification manually.
After the above steps, you can try to start your app. If you encountered an error related to something like The number of method references in a .dex file cannot exceed 64k, you can add the followings to your android/app/build.gradle file
android {
...
defaultConfig {
...
multiDexEnabled true
}
...
}
After installing the package, you can call the methods provided by the library to change the windowSoftInputMode as you need.
For example, assuming you have a default windowSoftInputMode of adjustResize, and you want to use adjustPan within ScreenA, you can call AndroidKeyboardAdjust.setAdjustPan() when ScreenA mount, and reset the windowSoftInputMode to adjustResize on unmount by calling AndroidKeyboardAdjust.setAdjustResize()
As of 2023, the best choice is react-native-avoid-softinput. react-native-android-keyboard-adjust isn't supported anymore.
You can use AvoidSoftInput.setAdjustPan and AvoidSoftInput.setAdjustResize.
I use custom hook to disable my default behavior on some screens.
import { useCallback } from 'react'
import { AvoidSoftInput } from 'react-native-avoid-softinput'
import { useFocusEffect } from '#react-navigation/native'
import { Platform } from 'react-native'
function useAndroidKeyboardAdjustNothing() {
useFocusEffect(
useCallback(() => {
if (Platform.OS === 'android') {
AvoidSoftInput.setAdjustNothing()
AvoidSoftInput.setEnabled(true)
}
return () => {
if (Platform.OS === 'android') {
AvoidSoftInput.setEnabled(false)
AvoidSoftInput.setAdjustResize()
}
}
}, []),
)
}

React Native startup optimization

I am looking for a way to optimize the startup time of a pure react native mobile app.
As a JavaScript framework, is that possible to bundle the JavaScript files into separated files, say something like common.js and app.js. I was searching via Google with keywords something like "react native webpack" stuff but it seems like all these libraries are deprecated or out of date, such as react-native-webpack-server, react-native-webpack-starter-kit etc.
I am wondering if anybody here is also looking for a way to optimize the JavaScript bundle in react native. Or, maybe these third party bundle approach has been overcame by Facebook standard bundle?
You could dynamically load your component, in this way your bundle.js will contain only the fraction of js needed and as you navigate you will request the other different parts / fractions.
Rather than do the traditional way: import App from './containers/App/App'; you could do something like this:
class ImportedComponent extends Component {
state = {
component: null
}
componentWillMount() {
this.props.load()
.then((mod) => this.setState(() => ({
component: mod.default
})))
}
render() {
return this.props.children(this.state.component)
}
}
const App = (props) => (
<ImportedComponent load={() => import('./containers/App/App')}>
{(Component) => Component === null ? <h6 className="loading-message">Loading...</h6> : <Component {...props}/>}
</ImportedComponent>
)
or you can lazy load your component itself. Let's say for example that I have Moment JS and I don't want to load it until it's needed. so what I could do:
1) Create a state and set it to null.
constructor(props){
super(props);
this.state = {
lazyLoadedComponent: () => null
}
}
2) Use async componentDidMount with await, try and catch and update the state lazyLoadedComponent on componentDidMount
async componentDidMount(){
try {
const Moment = await import('react-moment');
this.setState({ lazyLoadedComponent: (data)=>{
return React.createElement(Moment.default, {format:'MM/DD/YY'}, data)
}
});
}
catch(err) {
this.setState({ lazyLoadedComponent: <div>{`Failed to load component: ${err}`}</div> });
}
}
3) Call the component on the render:
{this.state.lazyLoadedComponent(value.createdOn)}
By following these 2 examples you should, hopefully, be looking at a bundle.js under 250KB.
As a possible solution you can use ram-bundle format, that metro bundler provides.
In this case you will not load the entire js-bundle - you will load only part, that you need at a startup (in a lot of application are a lot of places, which user may not even see, and this feature allow you load such parts, only when they are required). So you can simplify your entry point and load only small piece of your bundle.
You can look at react-native-bundle-splitter. This library well integrated with almost all popular navigation libraries and allows you to postpone a loading of specific routes. For example, if you have a login screen, you can load at start up only this screen, and all others load in background or start the loading of them, only when user can see them.