How to refresh page on goBack with React Navigation V5 - react-native

I want to refresh page data when I navigate back to it.
Here I'm going back:
.then((response) => response.json())
.then((responseData) => {
console.log(responseData);
this.renderResults(responseData)
setTimeout(() => {
this.props.navigation.navigate('HomeScreen');
}, 100)
})
.catch((error) => {
console.error(error);
});

when you go back you can add focus listener and refresh the data
import * as React from 'react';
import { View } from 'react-native';
function AppScreen({ navigation }) {
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
// The screen is focused
// Call any action and update data
});
// Return the function to unsubscribe from the event so it gets removed on unmount
return unsubscribe;
}, [navigation]);
return <View />;
}
source : https://reactnavigation.org/docs/function-after-focusing-screen/

Instead of using focus listener, use the useFocusEffect hook which is designed for such use cases and provides a way to cleanup side-effects like useEffect does.
import * as React from 'react';
import { useFocusEffect } from '#react-navigation/native';
function App({ navigation }) {
useFocusEffect(
React.useCallback(() => {
let cleanedUp = false;
fetch('https://your/api')
.then((response) => response.json())
.then((responseData) => {
if (cleanedUp) {
// Ignore the results if the effect is no longer valid
// e.g. component was unfocused, not mounted anymore etc.
return
}
console.log(responseData);
renderResults(responseData);
setTimeout(() => {
navigation.navigate('HomeScreen');
}, 100);
})
.catch((error) => {
console.error(error);
});
return () => {
cleanedUp = true;
};
}, [navigation])
);
// Your component code
}
https://reactnavigation.org/docs/function-after-focusing-screen/#triggering-an-action-with-the-usefocuseffect-hook

Related

Display datas with Axios (React Native)

I am trying to display data that I fetched with Axios. They came as an array. Because of this I cant show them. What should I do?
Here is my fetch code
componentDidMount() {
axios.post('http://192.168.1.106:80/partner_project_backend/project_list.php')
.then((response) => {
console.log(response.data)
})
.catch((error) => {
console.error(error);
});
}
Here is my console.log
I'm guessing you are getting the API response correctly and your only intention is to display the data in your application. If so, you could use the FlatList component from React Native
import React from 'react';
import { FlatList, Text } from 'react-native';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
};
}
componentDidMount() {
axios.get('http://192.168.1.106:80/partner_project_backend/project_list.php')
.then((response) => {
this.setState({ data: response.data });
})
.catch((error) => {
console.error(error);
});
}
render() {
return (
<FlatList
data={data}
renderItem={({ item }) => (
<Text>{item.name}</Text> // render your view here
)}
keyExtractor={item => item.id}
/>
);
}
}
React more about FlatList at https://reactnative.dev/docs/flatlist
To fetch data you have to use get method NOT post
this.state ={ data : null }
componentDidMount(){
axios.get('http://192.168.1.106:80/partner_project_backend/project_list.php')
.then((response) => {
this.setState({ data : response.data })
})
.catch((error) => {
console.error(error);
});
}

Check if screen is getting blurred or focus in React native?

i am using this
useEffect(() => {
const navFocusListener = navigation.addListener('didFocus', () => {
console.log('focus');
});
return () => {
navFocusListener.remove();
};
}, []);
I am using this code also tried other listeners. but there is no benefit, i am using react-native-immediate-call package for ussd dialing but as it doesn't have any callback. So i i call this function a dialer open for dialing for the USSD code. So now i want that when ussd dialing completes then comes back to screen and a api will call to get response. So how can i detect that USSD dialing is running running or completed so that i can make a request to the api.
For focus listener; you must change 'didFocus' to 'focus', If you are using react navigation v5+ and you should update like below:
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
// do something
});
return unsubscribe;
}, []);
You can examine its documentation from here.
in react-navigation 5 you can do this to check screen is focus or blur,
try this in react navigation 5 using usefocuseffect-hook
useEffect(
() => navigation.addListener('focus', () => {}),
[navigation]
);
useEffect(
() => navigation.addListener('blur', () => {}),
[navigation]
);
Try this thanks
import { NavigationEvents } from "react-navigation";
callback=()=>{
alert('I m always working when you come this Screen')
}
in return (
<Your Code>
<NavigationEvents onWillFocus={() => callback()} />
<Your Code/>
)
Actually, you need to detect app state if it is in foreground or background or needs to add callback function into react-native-immediate-call by writing native code of android or ios package like this
import React, { useRef, useState, useEffect } from "react";
import { AppState, StyleSheet, Text, View } from "react-native";
const AppStateExample = () => {
const appState = useRef(AppState.currentState);
const [appStateVisible, setAppStateVisible] = useState(appState.current);
useEffect(() => {
AppState.addEventListener("change", _handleAppStateChange);
return () => {
AppState.removeEventListener("change", _handleAppStateChange);
};
}, []);
const _handleAppStateChange = (nextAppState) => {
if (
appState.current.match(/inactive|background/) &&
nextAppState === "active"
) {
console.log("App has come to the foreground!");
}
appState.current = nextAppState;
setAppStateVisible(appState.current);
console.log("AppState", appState.current);
};
return (
<View style={styles.container}>
<Text>Current state is: {appStateVisible}</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
});
export default AppStateExample;

Possible unhandled promise rejection on hardware back press

I have set up a store function
export const storeData = async text => {
try {
await AsyncStorage.getItem("notes")
.then((notes) => {
const noteList = notes ? JSON.parse(notes) : [];
noteList.push(text);
AsyncStorage.setItem('notes', JSON.stringify(noteList));
});
} catch (error) {
console.log("error saving" + error);
}
};
When calling from the header back button it works as intended
navigation.setOptions({
headerLeft: () => (
<HeaderBackButton onPress={() => {
storeData(text).then(() => {
navigation.goBack();
}
}} />
)
});
But when using it from the hardware back button it gives me an "unhandled promise rejection, undefined is not an object. evaluating _this.navigation".
useEffect(() => {
const backHandler = BackHandler.addEventListener("hardwareBackPress", () => {
storeData(text).then(() => {
this.navigation.goBack();
});
});
return () => backHandler.remove();
}, [text]);
Can anyone see what might cause this behaviour?
replace this by props. thiskey word is used mainly in class components here i its a functional components so navigation is reached by props.navigation
The full code would look like
function EditNoteScreen({ navigation }) {
const [text, setText] = useState("");
const backAction = () => {
storeData(text).then(() => {
Keyboard.dismiss();
navigation.goBack();
});
}
useEffect(() => {
const backHandler = BackHandler.addEventListener("hardwareBackPress", () => {
backAction();
});
navigation.setOptions({
headerLeft: () => (
<HeaderBackButton onPress={() => {
backAction();
}} />
)
});
return () => backHandler.remove();
}, [text]);
If I simply have my storage function run with the hardware back press the code will work and the hardware back buttons default behavior will take me back, but then the new item will not show up until refreshed, which is why i want the back behavior delayed until saving is done.
One way to ignore this would simply be to update the flatlist again on state change, but I would rather have the information there from the refresh rather then popping in.

navigation.navigate does not work on one of useEffect();

I am developing a code and always need the user to enter the application to check if there is an update, if there is to send the user to an information screen. But for some reason when I use navigation.navigate ('update') it doesn't work, but console.log ("oi"); above it works. What happens is normal is that last useEffect() executes the navigation.navigate ('Menu'); In the console does not show any kind of error.
Code:
useEffect(() => {
async function verifyVersion() {
await api.post('/version', {
version: 'v1.0'
}).then((response)=>{
console.log("oi");
navigation.navigate('update');
});
}
verifyVersion();
}, []);
useEffect(() => {
async function autoLogon() {
if(await AsyncStorage.getItem("Authorization") != null){
await api.post('/checkToken', null, {
headers: { 'Authorization': 'EST ' + await AsyncStorage.getItem("Authorization") }
}).then((res)=>{
navigation.navigate('Menu');
}).catch(function (error){
if(error.response.data.showIn == "text"){
setShowInfo(true);
if(error.response.data.level == 3){
setColorInfo(false);
}else{
setColorInfo(true);
}
setInfoText(error.response.data.error);
}else{
setshowBox(true);
if(error.response.data.level == 3){
setcolorBox(false);
}else{
setcolorBox(true);
}
setboxText(error.response.data.error);
}
});
}
}
autoLogon();
}, []);
Routes:
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import Login from './pages/Login';
import read from './pages/read';
import Menu from './pages/Menu';
import Resultado from './pages/Resultado';
import NoConnection from './pages/NoConnection';
import update from './pages/update';
const Routes = createAppContainer(
createSwitchNavigator({
Login,
Menu,
read,
Resultado,
NoConnection,
update
})
);
export default Routes;
Write the navigate function call in setTimeOut for 500ms. it works
fine for me
useEffect(() => {
....
setTimeOut(() => navigation.navigate('Dashboard'), 500);
}, []);
In react-navigation, screen mounting works differently from react component mounting. You need to use a focus listener like this:
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
if (!someCondition) navigation.navigate('someScreen');
});
return unsubscribe;
}, [navigation]);
More on the topic can be found here and here

How to pass the value of useState to BackHandler.addEventListener

I'm using React Hooks and when I create an event listener for android back press handler, the state inside the callback function handler is empty!
In class components it works fine!
'use strict';
import React, { useState, useEffect } from 'react';
import { BackHandler } from 'react-native';
import TextInput from '../../../../components/TextInput';
export default function Foo() {
const [comment, setComment] = useState('');
useEffect(() => {
const handler = BackHandler.addEventListener(
'hardwareBackPress',
handleValidateClose
);
return () => handler.remove();
}, []);
const handleValidateClose = () => {
/* Here is empty */
console.log(comment);
};
return <TextInput onChangeText={setComment} value={comment} />;
}
The value should be the useState changed
handleValidateClose should be on your dependency array.
You can use your function outside the useEffect but should use with useCallback.
const handleValidateClose = useCallback(() => {
console.log(comment);
return true;
}, [comment]);
useEffect(() => {
const handler = BackHandler.addEventListener(
'hardwareBackPress',
handleValidateClose,
);
return () => handler.remove();
}, [handleValidateClose]);
You can also move the definition to inside useEffect, and add a comment as a dependency.
useEffect(() => {
const handleValidateClose = () => {
console.log(comment);
return true;
};
const handler = BackHandler.addEventListener(
'hardwareBackPress',
handleValidateClose,
);
return () => handler.remove();
}, [comment]);
To clean things up, create a useBackHandler.
export default function useBackHandler(handler) {
useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', handler);
return () => {
BackHandler.removeEventListener('hardwareBackPress', handler);
};
});
}
And use it like this:
const handleValidateClose = () => {
console.log(comment);
return true;
};
useBackHandler(handleValidateClose);
Please config your project to use the eslint-plugin-react-hooks. That's a common pitfalls that the plugin would help you with.