react-native re-run function on navigating back - javascript

I'm using react-navigation to navigate between screens, now in my "cases.js" I have a fetch method that gets the cases from the API when the user click on one it loads another page with the clicked case to either accept or deny the case itself.
Either way the user will be redirected to the "cases.js" page if the user accepts the case I no longer need the case to be available on the "cases.js" page list.
Here is my cases.js file
export default class PendingCases extends Component {
constructor(props) {
super(props);
this.state = { cases : [], user : '', refreshing : false }
}
componentDidMount = async () => {
await this._getUser();
await this._getCases();
}
_getUser = async () => {
let user = await AsyncStorage.getItem('user');
await this.setState({ user : JSON.parse(user) })
}
_getCases = async () => {
try {
await this.setState({ refreshing : true })
let pendingCases = await fetch('http://192.168.1.101:1337/user/cases?status=pending&userType=patient&id=' + this.state.user.id);
let response = await pendingCases.json();
await this.setState({ cases : response.cases });
await this.setState({ refreshing : false })
} catch (err) {
console.log(err);
}
}
render() {
let casesArray = this.state.cases.map((singleCase, index) => {
return (
<View key={ index }>
<TouchableOpacity onPress={ () => this.props.navigation.navigate('SelectedCaseDetails') } style={ styles.caseButton }>
<View>
<View style={{ marginBottom: 10, marginTop: 5 }}>
<LinearTextGradient locations={[0, 1]} start={{x: 0, y: 0}} end={{x: 1, y: 0}} colors={['#a4d294', '#3ac6f3']} style={{ fontWeight: 'bold' }}>
{singleCase.doctor.name}
</LinearTextGradient>
<Text style={{ position: 'absolute', right: 0, fontWeight: '600', color: 'black'}}> 00231 </Text>
</View>
<View style={{ marginBottom: 10 }}>
<Text> {singleCase.additionalInformation} </Text>
</View>
<View style={{ marginBottom: 10, flex : 1, flexDirection: 'row'}}>
<Image style={ styles.statusImage } source={require('../images/status.png')} />
<Text style={{ marginRight : 30, color : 'rgba(0, 0, 0, .8)', flex : 8}}>
Status <Text style={{ color : 'rgb(240, 151, 166)', marginLeft : 60 }}> {singleCase.status} </Text> </Text>
<Text style={{ position: 'absolute', right: 0, fontWeight: '300', color: 'grey'}}> { parsedDate } </Text>
</View>
</View>
</TouchableOpacity>
</View>
)
});
return (
<View>
{ casesArray }
</View>
)
}
}
How can I re-run the this._getCases() function when I redirect the user from the one-level deep page ?
I'm redirecting the user the same way as navigating to any other screen
this.props.navigation.navigate('CasesScreen')

If your component is already mounted, you can use react-navigation's listeners to check whether the component is focused or not.
You'll need
didFocus: the screen focused (if there was a transition, the transition completed)
componentDidMount () {
this._getUser();
this._onFocusListener = this.props.navigation.addListener('didFocus', (payload) => {
this._getCases();
});
}
and remove it once the component gets unmounted.
componentWillUnmount () {
this._onFocusListener.remove()
}

Related

How to save route.params with asyncstorage?

Srry if the title makes no sense. Don't know a better title.
How can I save route.params items that I pass to my second screen using AsyncStorage?
In my first screen i have a bunch of data in a FlatList that can be opened with a Modal. Inside that Modal I have a TouchableOpacity that can send the data thats inside the Modal to my second screen. The data that has been passed to the second screen is passed to a FlatList. The data in the FlatList should be saved to AsyncStorage. Tried alot of things getting this to work, but only getting warning message
undefined. Code below is the most recent progress.
Using React Navigation V5.
FIRST SCREEN
const [masterDataSource, setMasterDataSource] = useState(DataBase);
const [details, setDetails] = useState('');
<TouchableOpacity
onPress={() => {
const updated = [...masterDataSource];
updated.find(
(item) => item.id === details.id,
).selected = true;
setMasterDataSource(updated);
navigation.navigate('cart', {
screen: 'cart',
params: {
items: updated.filter((item) => item.selected),
},
});
setModalVisible(false);
}}>
<Text>Add to cart</Text>
</TouchableOpacity>
SECOND SCREEN
import React, { useEffect, useState } from 'react';
import { View, Text, FlatList, TouchableOpacity } from 'react-native';
import { useTheme } from '../Data/ThemeContext';
import AsyncStorage from '#react-native-async-storage/async-storage';
import Ionicons from 'react-native-vector-icons/Ionicons';
export default function ShoppingList({ route, navigation }) {
const [shoppingList, setShoppingList] = useState([]);
const { colors } = useTheme();
const todo = () => {
alert('Todo');
};
useEffect(() => {
restoreShoppingListAsync();
}, []);
const shoppingListAsync = () => {
const shoppingList = route.params && route.params.items;
setShoppingList(list);
storeShoppingList(list);
};
const asyncStorageKey = '#ShoppingList';
const storeShoppingListAsync = (list) => {
const stringifiedList = JSON.stringify(list);
AsyncStorage.setItem(asyncStorageKey, stringifiedList).catch((err) => {
console.warn(err);
});
};
const restoreShoppingListAsync = () => {
AsyncStorage.getItem(asyncStorageKey)
.then((stringifiedList) => {
console.log(stringifiedList);
const parsedShoppingList = JSON.parse(stringifiedList);
if (!parsedShoppingList || typeof parsedShoppingList !== 'object')
return;
setShoppingList(parsedShoppingList);
})
.then((err) => {
console.warn(err);
});
};
const RenderItem = ({ item }) => {
return (
<View>
<TouchableOpacity
style={{
marginLeft: 20,
marginRight: 20,
elevation: 3,
backgroundColor: colors.card,
borderRadius: 10,
}}>
<View style={{ margin: 10 }}>
<Text style={{ color: colors.text, fontWeight: '700' }}>
{item.name}
</Text>
<Text style={{ color: colors.text }}>{item.gluten}</Text>
<Text style={{ color: colors.text }}>{item.id}</Text>
</View>
</TouchableOpacity>
</View>
);
};
const emptyComponent = () => {
return (
<View style={{ alignItems: 'center' }}>
<Text style={{ color: colors.text }}>Listan är tom</Text>
</View>
);
};
const itemSeparatorComponent = () => {
return (
<View
style={{
margin: 3,
}}></View>
);
};
return (
<View
style={{
flex: 1,
}}>
<View
style={{
padding: 30,
backgroundColor: colors.Textinput,
elevation: 12,
}}>
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<TouchableOpacity onPress={() => navigation.goBack()}>
<Ionicons name="arrow-back-outline" size={25} color="#fff" />
</TouchableOpacity>
<Text style={{ color: '#fff', fontSize: 20 }}>Inköpslista</Text>
<TouchableOpacity>
<Ionicons
name="trash-outline"
size={25}
color="#fff"
onPress={() => todo()}
/>
</TouchableOpacity>
</View>
</View>
<View style={{ flex: 1, marginTop: 30 }}>
<FlatList
data={shoppingList}
renderItem={RenderItem}
ListEmptyComponent={emptyComponent}
ItemSeparatorComponent={itemSeparatorComponent}
initialNumToRender={4}
maxToRenderPerBatch={5}
windowSize={10}
removeClippedSubviews={true}
updateCellsBatchingPeriod={100}
showsVerticalScrollIndicator={true}
contentContainerStyle={{ paddingBottom: 20 }}
/>
</View>
</View>
);
}
As you are using async storage to maintain the cart.
I would suggest an approach as below
Update the asyn storage when new items are added to or removed from the cart
Retrieve the items from the cart screen and show the items there
Before you navigate store the items like below
AsyncStorage.setItem(
'Items',
JSON.stringify(updated.filter((item) => item.selected))
).then(() => {
navigation.navigate('Cart', {
items: updated.filter((item) => item.selected),
});
});
The cart screen would be something like below
function Cart({ navigation, route }) {
const [data,setData]=useState([]);
React.useEffect(() => {
async function fetchMyAPI() {
const value = await AsyncStorage.getItem('Items');
setData(JSON.parse(value));
}
fetchMyAPI();
}, []);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button title="Go back" onPress={() => navigation.goBack()} />
<FlatList
data={data}
renderItem={RenderItem}
/>
</View>
);
}
Working Example
https://snack.expo.io/#guruparan/cartexample

react native : is there any way that the modal will disappear alone after a few seconds?

is there any way that the modal will disappear alone after a few seconds without onpress?
I try to disappear the modal with animation after 2 second without the "ENTER" button.
i try to do animationOutTiming={1000} and backdropTransitionOutTiming={4000} but it doesnt disappear alone .
how should i do it ?
this is my example code :
export default class Example extends Component {
constructor(props) {
super(props);
this.state = {
visibleModal: 3,
azureLoginObject: {},
loginSuccess: false
};
this.azureInstance = new AzureInstance(credentials);
this._onLoginSuccess = this._onLoginSuccess.bind(this);
}
_renderButton = () => (
<TouchableOpacity
onPress={() => this.setState({ visibleModal: false })}>
<LinearGradient
colors={['#4c669f', '#3b5998', '#192f6a']}
style={{
height: 80,
width: 180,
borderRadius: 10,
backgroundColor: "#2196F3",
justifyContent: 'center',
alignItems: 'center',
marginTop: 50,
}}>
<Text style={{ color: 'white', fontSize: 20, fontWeight: 'bold' }}>ENTER</Text>
</LinearGradient>
</TouchableOpacity>
);
_onLoginSuccess() {
this.azureInstance.getUserInfo().then(result => {
this.setState({
loginSuccess: true,
azureLoginObject: result,
});
console.log(result);
}).catch(err => {
console.log(err);
})
}
renderWelcomeMsg = (currentTime = new Date()) => {
const currentHour = currentTime.getHours()
const splitAfternoon = 12; // 24hr time to split the afternoon
const splitEvening = 17; // 24hr time to split the evening
if (currentHour >= splitAfternoon && currentHour <= splitEvening) {
return 'צהריים טובים,';
} else if (currentHour >= splitEvening) {
return 'ערב טוב,';
}
return 'בוקר טוב,';
}
render() {
if (!this.state.loginSuccess) {
return (
<AzureLoginView
azureInstance={this.azureInstance}
onSuccess={this._onLoginSuccess}
/>)
}
if (this.state.visibleModal === 3) {
const { givenName } = this.state.azureLoginObject;
const { userPrincipalName } = this.state.azureLoginObject;
storeService.saveItem('userPrincipalName', userPrincipalName)
return (
<View style={styles.container}>
<Modal
isVisible={this.state.visibleModal === 3}
animationInTiming={1000}
animationOutTiming={1000}
backdropTransitionInTiming={4000}
backdropTransitionOutTiming={4000}
animationIn={'flipInY'}
>
<LinearGradient
colors={['#43D4FF', 'white']}
style={{ borderRadius: 10 }}>
<View style={styles.modalContent}>
<Text style={{
fontWeight: "bold",
fontSize: 35,
justifyContent: 'center',
alignItems: 'center',
}}>{this.renderWelcomeMsg()} {givenName}
</Text>
<View style={styles.buttonContainer}>
{this._renderButton()}
</View>
</View>
</LinearGradient>
</Modal>
</View>
);
}
return (
<PlacesNavigator />
);
}
}
why not start a timeout after the modal shows which changes the state after a few seconds?
setTimeout(() => {
this.setState({ visibleModal: false});
}, 3000) // 3 seconds
You start this, once the modal is rendered
Edit:
Assuming below is the code for your modal
if (this.state.visibleModal === 3) {
const { givenName } = this.state.azureLoginObject;
const { userPrincipalName } = this.state.azureLoginObject;
storeService.saveItem('userPrincipalName', userPrincipalName)
// let's add the setTimeout
setTimeout(() => {
// or whatever the state is, that disables the modal for you
this.setState({ visibleModal: false});
}, 3000) // 3 seconds
return (
<View style={styles.container}>
<Modal
isVisible={this.state.visibleModal === 3}
animationInTiming={1000}
animationOutTiming={1000}
backdropTransitionInTiming={4000}
backdropTransitionOutTiming={4000}
animationIn={'flipInY'}
>
<LinearGradient
colors={['#43D4FF', 'white']}
style={{ borderRadius: 10 }}>
<View style={styles.modalContent}>
<Text style={{
fontWeight: "bold",
fontSize: 35,
justifyContent: 'center',
alignItems: 'center',
}}>{this.renderWelcomeMsg()} {givenName}
</Text>
<View style={styles.buttonContainer}>
{this._renderButton()}
</View>
</View>
</LinearGradient>
</Modal>
</View>
);
}
Things you might have to consider:
What happens when the component is dismounted?
The timer will still run and try to set the state.
Think about clearing the timeout on unmounts to be safe.

is there way to print and show the total sum objects that arrive from my JSON in a footer at the bottom of the screen?

At my example, the function “getData” loading my data, but after the loading, I try to print and show the total sum of the objects that came from JSON in a footer at the bottom of the screen.
and I don't really know how to do it.
I don't understand how to solve this issue coz I have tried many ways.
This is my example:
export default class MainScreen extends Component {
constructor(props) {
super(props);
this.state = { data: [] };
}
getData = () => {
this.setState({ isLoading: true })
axios.get("https://rallycoding.herokuapp.com/api/music_albums")
.then(res => {
this.setState({
isLoading: false,
data: res.data
});
console.log(res.data);
});
}
componentDidMount() {
this.props.navigation.setParams({getData: this.getData}); //Here I set the function to parameter
this.getData()
}
renderItem(item) {
const { title, artist} = item.item;
return (
<TouchableOpacity
onPress={() => this.props.navigation.navigate("Settings")}
>
<Card
containerStyle={{
borderColor: "black",
padding: 20,
height: 100,
backgroundColor: "#e6e6ff",
borderBottomEndRadius: 10,
borderTopRightRadius: 10,
borderBottomStartRadius: 10,
}}
>
<View
style={{
paddingVertical: 15,
paddingHorizontal: 10,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center"
}}
>
<Icon name="chevron-right" size={30} color={"grey"} justifyContent={"space-between"} />
<Text style={styles.name}>
{title+ " " + artist}
</Text>
{/* <Text style={styles.vertical} numberOfLines={2}></Text> */}
</View>
</Card>
</TouchableOpacity>
);
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, paddingTop: 230 }}>
<Text
style={{ alignSelf: "center", fontWeight: "bold", fontSize: 20 }}
>
loading data...
</Text>
<ActivityIndicator size={'large'} color={'#08cbfc'} />
</View>
);
}
return (
<View style={styles.container}>
<FlatList
data={this.state.data}
renderItem={this.renderItem.bind(this)}
keyExtractor={item => item.id}
/>
</View>
);
}
}
/////////////////////////////////////////////////////////
MainScreen.navigationOptions = navData => {
return {
headerTitle: 'melon',
headerRight: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title=**"sync button"**
iconName={Platform.OS === "android" ? "md-sync" : "ios-sync"}
onPress={() => {
navData.navigation.navigate("getData");// here i trying to use the function
console.log("MT DATA====", navData.navigation.getParam(this.getData))//NO DATA
}}
/>
</HeaderButtons>
)
};
};
hope could you help in this situation coz its really confused me this key prop
If you are sure that all elements are unique, you can just use this key extractor in FlatList -
keyExtractor={(_, index) => String(index)}
this will ensure the uniqueness of all items in your flatlist
Probably you should set navigation param like
getData = () => {
this.setState({ isLoading: true })
axios.get("https://rallycoding.herokuapp.com/api/music_albums")
.then(res => {
this.setState({
isLoading: false,
data: res.data
});
this.props.navigation.setParams({data: res.data});
console.log(res.data);
});
}
and then in
headerRight: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title=**"sync button"**
iconName={Platform.OS === "android" ? "md-sync" : "ios-sync"}
onPress={() => {
const data = navData.navigation.getParam("data");
console.log("MT DATA====", data);
}}
/>
</HeaderButtons>
)

React native How to return a value from a function to the component

Im getting the 2 user authenticated from firebase database but how can I return a value from the function or is there any other solution to the authenticated user
firebase.auth().onAuthStateChanged(user => {
if (user) {
firebase.database().ref('Usersyeah/').on('child_added', function (getdata) {
var newData = getdata.val().User
if (user.email == getdata.val().Email ){
if (getdata.val().User === 'User') {
var routes = [
{title: "Home",route: "Home",}
{title: "Pending Request",route: "Request"}]
} else {
var routes = [
{title: "USER",route: "Home"}
]
}
}
getdata.val().User })
});
} else {
}
})
return (
<View>
<TouchableOpacity style={{ backgroundColor: 'green', margin: 10, padding: 10 }}
onPress={this.mysubmit.bind(this)}>
<Text style={{ color: '#fff', alignItems: 'flex-end' }}> SUBMIT </Text>
</TouchableOpacity>
<Image
style={{ width: 250, height: 200 }}
source={require('../myimage/durian.jpg')}
/>
{
routes.map(e => (
<TouchableOpacity style={styles.link} onPress={_ => this.navigate(e.route)}>
<Text style={{ fontSize: 14 }}>{e.title}</Text>
</TouchableOpacity>
)
)
}
</View>
)
}
A way could be to declare an instance variable on component like
myComponent{
constructor(props){
this.valToBeReturned;
}
}
And then, inside function you can initialize it with the value you want:
theFunction(user=>{
this.valToBeReturned = getdata.val().User //for example
})
In this way, you have the value you want on this.valToBeReturned outside the function scope.

React native flatlist item stay checked; props changed

I have a really big problem and I don't know what I'm doing wrong. I also tried to debug everything and I didn't find any solution.
First of all lets say I have 2 components. FROM component A I send some props (array) to component B. I component B I load that props into my state and than I change some data in flatlist and store it on my state in that component. When I go back to previous screen, where is component A and going back to B, that flatlist is still the same and also PROPS stays the same.
Initial props from screen A: (when I firstly go to B component)
"listOfStudents":[{"key":"Suana Kristovski","id":"1358","checked":false,"o":false,"n":false}]
When I change item in flatlist and going back this is the props that arrived into component B:
listOfStudents":[{"key":"Suana Kristovski","id":"1358","checked":true,"o":false,"n":false}]
checked from false -> true,
Problem is that everything I do, I only change my state when item is changed in my flatlist.
Code in screen B:
componentDidMount() {
//console.log('Izvedem se vedno');
console.log('List of students Diary hours: ' + JSON.stringify(this.props.listOfStudents));
this.setState({
data: this.props.navigation.state.params.props.listOfStudents,
textOpombe: this.props.navigation.state.params.props.notes,
textVsebinaUre: this.props.navigation.state.params.props.lesson,
finished: this.props.navigation.state.params.props.finished,
absent: parseInt(this.props.navigation.state.params.props.apsent.substring(0,1)),
});
if(this.props.navigation.state.params.props.listOfStudents.length >= 2) {
this.setState({
height: 130
});
}
this.props.navigation.addListener('willBlur', (playload)=>{
});
}
My flatlist:
<FlatList
ref={(list) => this.myList = list}
style={[styles.flatList,{height: this.state.height}]}
data={this.state.data}
scrollEnabled = {this.state.scrollingChild}
contentContainerStyle={{ padding: 15 }}
renderItem={({ item }) => (
<View style={styles.listItemStyle}>
<View style={{flexDirection: 'row', marginBottom: 7, }}>
{
item.checked &&
<TouchableOpacity
onPress={this.changeCheckedToFalse.bind(this,item)}>
<View style={styles.checked} />
</TouchableOpacity> ||
<TouchableOpacity
onPress={this.changeCheckedToTrue.bind(this,item)}>
<View style={styles.unchecked} />
</TouchableOpacity>
}
<Text style={{color: '#000', opacity: 0.6}}>{item.key}</Text>
{
item.checked &&
<View style={{position: 'absolute', right: 0 }}>
<View style={{flexDirection: 'row'}} >
{
item.o &&
<TouchableOpacity
style={[styles.touchable1Ch,styles.iconStyle1]}
onPress={this.changeSelectionO.bind(this,item)}>
<Text style={{color: '#fff', fontSize: 18, alignSelf: 'center' }}>O</Text>
</TouchableOpacity> ||
<TouchableOpacity
style={[styles.touchable1,styles.iconStyle1]}
onPress={this.changeSelectionO.bind(this,item)}>
<Text style={{color: '#fff', fontSize: 15, alignSelf: 'center' }}>O</Text>
</TouchableOpacity>
}
{
item.n &&
<TouchableOpacity
style={[styles.touchable2Ch,styles.iconStyle1]}
onPress={this.changeSelectionN.bind(this,item)}>
<Text style={{color: '#fff', fontSize: 18, alignSelf: 'center' }}>N</Text>
</TouchableOpacity> ||
<TouchableOpacity
style={[styles.touchable2,styles.iconStyle1]}
onPress={this.changeSelectionN.bind(this,item)}>
<Text style={{color: '#fff', fontSize: 15, alignSelf: 'center' }}>N</Text>
</TouchableOpacity>
}
</View>
</View>
}
</View>
{
this.props.navigation.state.params.props.listOfStudents !== undefined && this.props.navigation.state.params.props.listOfStudents.length >= 2 ?
<View style={styles.line} /> : <Text></Text>
}
</View>
)}
keyExtractor={item => item.id}
/>
Methods for flatlist change item:
changeSelectionO(item) {
var data2 = this.state.data;
var itemIndex = data2.map(function (x) { return x.key; }).indexOf(item.key);
if(data2[itemIndex].o) {
data2[itemIndex].o = false;
} else {
data2[itemIndex].o = true;
if(data2[itemIndex].n) {
data2[itemIndex].n = false;
}
}
this.setState({
data: data2
});
//this.props.listOfStudents
}
changeSelectionN(item) {
var data2 = this.state.data;
var itemIndex = data2.map(function (x) { return x.key; }).indexOf(item.key);
if(data2[itemIndex].n) {
data2[itemIndex].n = false;
} else {
data2[itemIndex].n = true;
if(data2[itemIndex].o) {
data2[itemIndex].o = false;
}
}
this.setState({
data: data2
});
//this.props.listOfStudents
}
Can you please tell me why props is changing?

Categories

Resources