How to save history of component in react native using react native router flux - react-native

I am using react native router flux in android project for routing when i jump from one component to another than the history of last component is remove from stack i want to store components history please anyone.

instead of jump you can use
Action.keynameofyournextpage()
ex to go to page1 to page2
can use
Actions.page2()
in page 1

If you want to save a record of the components, use the AsyncStorage module to save them.
Example
import {AsyncStorage} from 'react-native';
//set data
_storeData = async () => {
try {
await AsyncStorage.setItem('componenthistory', componenthistory);
} catch (error) {
// Error saving data
}
};
...
//get data
_retrieveData = async () => {
try {
const value = await AsyncStorage.getItem('componenthistory');
if (value !== null) {
// We have data!!
console.log(value);
}
} catch (error) {
// Error retrieving data
}
};

Related

How to call API inside expo SplashScreen?

I'm new in react native so I can't figure out how to add an API call inside SplashScreen in react -native app. The context - I'm building a react-native app expo, which on app load should send API GET request to the backend to get order data, and based on that data I'm either displaying screen A(delivered) or B(order on it's way). I want to add this API call inside the SplashScreen when app still loads so when app is loaded there is no delay in getting API data and displaying screen A/B.
I have a simple useEffect function to call API like this:
const [data, setData] = useState{[]}
useEffect(() => {
const getData = async () => {
try {
const response = await axios.get(url);
if (response.status.code === 200 ) {
setData (response.data) // to save data in useState
}
} else if (response.status.code != 200) {
throw new Error();
}
} catch (error) {
console.log(error);
}
};
getData();
}, []);
and then in the return:
if (data.order.delivered) {
return <ScreenA />
}
else if (!data.order.delivered) {
return <ScreenB />
else {return <ScreenC />}
The issue is that sometimes if API is slow, then after splash screen app has a white screen, or ScreenC can be seen. How can I call API in the splashscreen while app is loading and have a nicer ux?
you can make a custom hook with simple UseState and put it after you've fetched your data
const [loading, setLoading] = useState(true)
...
useEffect(() => {
const getData = async () => {
try {
const response = await axios.get(url);
if (response.status.code === 200 ) {
setData (response.data)
// When data is ready you can trigger loading to false
setLoading(false)
}
...
and After that, you can use a Simple If statement on top of your app.js file
like this
if (!loaded) {
return <LoadingScreen/>; // whetever page you want to show here ;
}
you can use expo expo-splash-screen to achieve this goal:
call this hook on mount...
import * as SplashScreen from 'expo-splash-screen';
const [appIsReady, setAppIsReady] = useState(false);
useEffect(() => {
async function prepare() {
try {
// Keep the splash screen visible while we fetch resources
await SplashScreen.preventAutoHideAsync();
// Pre-load fonts, make any API calls you need to do here
await Font.loadAsync(Entypo.font);
// Artificially delay for two seconds to simulate a slow loading
// experience. Please remove this if you copy and paste the code!
await new Promise(resolve => setTimeout(resolve, 2000));
} catch (e) {
console.warn(e);
} finally {
// Tell the application to render
setAppIsReady(true);
}
}
prepare();
}, []);
you can also check expo doc

What is the best way in react native to fetch data and use it globally without redux?

I'm building an App without Redux and wonder what is the best way and where is the best place to fetch data from an API and store it globally, so it can be filtered, enhanced and displayed in different views for each case?
You can go for ReactQuery it is a data fetching library, it makes fetching, caching, synchronizing and updating server state easy.
import { QueryClient, QueryClientProvider, useQuery } from 'react-query'
const queryClient = new QueryClient()
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<FirstComponent />
<SecondComponent />
</QueryClientProvider>
)
}
function FirstComponent() {
// fetch some data
const { isLoading, error, data } = useQuery('myData', fetchData)
if (isLoading) return 'Loading...'
if (error) return 'An error has occurred: ' + error.message
return (
<div>
<h1>{data.name}</h1>
<p>{data.description}</p>
</div>
)
}
function SecondComponent() {
const queryClient = useQueryClient()
const invalidateData = () => {
// invalidate data, will trigger a refetch in FirstComponent
queryClient.invalidateQueries('myData')
}
return (
<div>
<button onClick={invalidateData}>
Click me to refetch data !
</button>
</div>
)
}
You can use AsyncStorage, It's like localStorage in Browsers and you can use it as the following code:
yarn add #react-native-async-storage/async-storage
import AsyncStorage from '#react-native-async-storage/async-storage';
// store item
const storeData = async (value) => {
try {
await AsyncStorage.setItem('#storage_Key', value)
} catch (e) {
// saving error
}
}
// get item
const getData = async () => {
try {
const value = await AsyncStorage.getItem('#storage_Key')
if(value !== null) {
// value previously stored
}
} catch(e) {
// error reading value
}
}

Get item value from AsyncStorage in react-native

I am a beginner and still try to learn to react native so help me!
I want to access AsyncStorage.getItem value outside the function.
I will further explain via code
This is my code :
import {AsyncStorage} from 'react-native';
set that value on screen1
AsyncStorage.setItem('mobileno', JSON.stringify(MobileNo));
try to get that value on screen 2
AsyncStorage.getItem('mobileno', (err, MobileNumber) => {
let abc = MobileNumber;
console.log("abc value " + abc)
})
let { MobileNo } = abc;
console.log({MobileNo})
I want to access that abc value outside the function as let { MobileNo } = abc; but it shows the error!
note : [console.log("abc value " + abc) works perfectlly ]
Error
can't find variable abc
question
So, how can I access that abc or that AsyncStorage value for the whole page [outside that function]; Because I want to use that value in other function too!
In short, I want that stored value in AsyncStorage to use it in other function.
Thank you for contributing your precious time
constructor(props) {
super(props);
this.state = {
mobileNumber: '',
};
}
componentDidMount() {
AsyncStorage.getItem('mobileno').then((mobileNo) => {
if(mobileNo){
this.setState({mobileNumber: mobileNo});
console.log(this.state.mobileNumber);
}
});
}
render() {
return(
<View>
<Text>{this.state.mobileNumber}</Text>
</View>
);
}
In this case async/await is not necessary because .then() is only called after the getItem() function is done fetching the item.
In your code abc is called out of scope. abc is only declared in your callback. An alternative can be to create a class method that returns that data. I personally find the async/await syntax much cleaner and easier understand the .then() chains.
docs show an example of this
_retrieveData = async () => {
try {
const value = await AsyncStorage.getItem('mobileno');
if (value !== null) {
// We have data!!
console.log(value);
return value;
}
} catch (error) {
// Error retrieving data
}
}
import {AsyncStorage} from 'react-native';
Above AsyncStorage is Deprecated, Moved to React-Native-Community
you can use now
1 :- yarn add #react-native-community/async-storage
2 :- react-native link #react-native-community/async-storage
Code :-
import AsyncStorage from '#react-native-community/async-storage';
storeData = async () => {
try {
await AsyncStorage.setItem('#storage_Key', 'stored value')
} catch (e) {
// saving error
}
}
getData = async () => {
try {
const value = await AsyncStorage.getItem('#storage_Key')
if(value !== null) {
// value previously stored
}
} catch(e) {
// error reading value
}
}
Link :- https://www.npmjs.com/package/#react-native-community/async-storage
use the link
https://github.com/react-native-community/async-storage
Install
$ yarn add #react-native-community/async-storage
Link
React Native 0.60+
CLI autolink feature links the module while building the app.
React Native <= 0.59
$ react-native link #react-native-community/async-storage
Note For iOS using cocoapods, run:
$ cd ios/ && pod install
See docs for manual linking guide
Upgrading to React Native 0.60+
New React Native comes with autolinking feature, which automatically links Native Modules in your project. In order to get it to work, make sure you unlink Async Storage first:
$ react-native unlink #react-native-community/async-storage
Usage
Import
import AsyncStorage from '#react-native-community/async-storage';
Store data
storeData = async () => {
try {
await AsyncStorage.setItem('#storage_Key', 'stored value')
} catch (e) {
// saving error
}
}
Read data
getData = async () => {
try {
const value = await AsyncStorage.getItem('#storage_Key')
if(value !== null) {
// value previously stored
}
} catch(e) {
// error reading value
}
}

Validate React Native Component with Asynchronous Work

I have a basic component that calls a webservice during the componentDidMount phase and overwrites the contents value in my state:
import React, {Component} from 'react';
import {Text} from "react-native";
class Widget extends Component {
constructor() {
super();
this.state = {
contents: 'Loading...'
}
}
async componentDidMount() {
this.setState(...this.state, {
contents: await this.getSomeContent()
});
}
render() {
return (
<Text>{this.state.contents}</Text>
)
}
async getSomeContent() {
try {
return await (await fetch("http://someurl.com")).text()
} catch (error) {
return "There was an error";
}
}
}
export default Widget;
I would like to use Jest snapshots to capture the state of my component in each one of the following scenarios:
Loading
Success
Error
The problem is that I have to introduce flaky pausing to validate the state of the component.
For example, to see the success state, you must place a small pause after rendering the component to give the setState method a chance to catch up:
test('loading state', async () => {
fetchMock.get('*', 'Some Content');
let widget = renderer.create(<Widget />);
// --- Pause Here ---
await new Promise(resolve => setTimeout(resolve, 100));
expect(widget.toJSON()).toMatchSnapshot();
});
I'm looking for the best way to overcome the asynchronicity in my test cases so that I can properly validate the snapshot of each state.
If you move the asynchronous call out of setState, you can delay setState until the network call has resolved. Then you can use setState's optional callback (which fires after the state change) to capture the state.
So, something like this:
async componentDidMount() {
var result = await this.getSomeContent()
this.setState(...this.state, {
contents: result
},
// setState callback- fires when state changes are complete.
()=>expect(this.toJSON()).toMatchSnapshot()
);
}
UPDATE:
If you want to specify the validation outside of the component, you could create a prop, say, stateValidation to pass in a the validation function:
jest('loading state', async () => {
fetchMock.get('*', 'Some Content');
jestValidation = () => expect(widget.toJSON()).toMatchSnapshot();
let widget = renderer.create(<Widget stateValidaton={jestValidation}/>);
});
then use the prop in the component:
async componentDidMount() {
var result = await this.getSomeContent()
this.setState(...this.state, {
contents: result
},
// setState callback- fires when state changes are complete.
this.props.stateValidaton
);
}

How to get the device token in react native

I am using react-native 0.49.3 version, My Question is how to get the device token in react native for both IOS and Android I tried with this link but it not working for me, right now I tried in IOS. how to resolve it can one tell me how to configure?
I tried different solutions and I've decided to use React Native Firebase.
Here you will find everything about Notifications.
Also, you can use the others libraries that come with Firebase, like Analytics and Crash Reporting
After set up the library you can do something like:
// utils/firebase.js
import RNFirebase from 'react-native-firebase';
const configurationOptions = {
debug: true,
promptOnMissingPlayServices: true
}
const firebase = RNFirebase.initializeApp(configurationOptions)
export default firebase
// App.js
import React, { Component } from 'react';
import { Platform, View, AsyncStorage } from 'react-native';
// I am using Device info
import DeviceInfo from 'react-native-device-info';
import firebase from './utils/firebase';
class App extends Component {
componentDidMount = () => {
var language = DeviceInfo.getDeviceLocale();
firebase.messaging().getToken().then((token) => {
this._onChangeToken(token, language)
});
firebase.messaging().onTokenRefresh((token) => {
this._onChangeToken(token, language)
});
}
_onChangeToken = (token, language) => {
var data = {
'device_token': token,
'device_type': Platform.OS,
'device_language': language
};
this._loadDeviceInfo(data).done();
}
_loadDeviceInfo = async (deviceData) => {
// load the data in 'local storage'.
// this value will be used by login and register components.
var value = JSON.stringify(deviceData);
try {
await AsyncStorage.setItem(config.DEVICE_STORAGE_KEY, value);
} catch (error) {
console.log(error);
}
};
render() {
...
}
}
Then you can call the server with the token and all the info that you need.