How to navigate to another page if payment is success - react-native

code is working when i placed this line of code just below onpress()
but inside success callback not working
check handle success
<TouchableOpacity
style={styles.item}
onPress={() => {
RazorpayCheckout.open({
...
theme: { color: "#f7b500" }
})
.then(data => {
***// handle success***
console.log(`Success: ${data.razorpay_payment_id}`);
console.log(reference)
**reference.navigation.navigate("ThankyouScreen", {
AvailablePoints: creditScorePoints - item.cash
});**
})
.catch(error => {
...
});
}}
>

What is reference? if it is this.props then Make sure it is defined globally.
Try to change your code with:
//on top of class
var reference = null;
//In componentDidMount
reference = this.props;

Related

Re render flat list when data change cause infinite loop React Native

I have two screens. Approve List and Approve Detail. When data approved in Approve Detail, page navigate to Approve List. Then approved data should disapear from FLatList. How to remove FlatList item when data approved? or how to re render FlatList when data change? Here is my code:
Approve List:
const Approve = ({ navigation }) => {
const [rekomendasi, setRekomendasi] = useState({})
// other code
const getRekomendasi = async (token, bagian) => {
try {
const response = await sippApi.get(`/penjaminan?bagian=${bagian}`, {
headers: {
Auth: token
}
});
setRekomendasi(response.data.data)
console.log(rekomendasi)
} catch (error) {
console.log(error)
}
}
useEffect(() => {
getToken();
getUserData()
getRekomendasi(token, userData.bagian);
}, [setToken, setUserData, rekomendasi]); // if I pass rekomendasi here, make infinite loop on api request
return (
<FlatList
onRefresh={() => onRefresh()}
refreshing={isFetching}
removeClippedSubviews
style={{ marginTop: 2 }}
data={rekomendasi}
keyExtractor={rekom => rekom.penjaminan.nomor_rekomendasi}
renderItem={({ item }) => {
return (
<TouchableOpacity onPress={() => navigation.navigate("ApproveDetail", { id: item.penjaminan.nomor_rekomendasi, bagian: userData.bagian })}>
<ApproveList
plafond={item.value}
kantor={item.nama_kantor}
nomor_rekomendasi={item.nomor_rekomendasi}
produk={item.skim}
/>
</TouchableOpacity>
)
}}
showsHorizontalScrollIndicator={false}
/>
)
}
If I pass value on second argument on UseEffect, it cause infinite loop on API request. If not, my FlatList cant re render when data change. What should I do?
Thanks for help
You have to remove the rekomendasi dependency in the useEffect to avoid infinite loop, it's only for init data :)
What is the purpose of onRefresh function in the FlatList ? Instead you could put the getRekomendasi function to trigger a new call and your data will be updated
try to separate the functions to two useEffects
useEffect(() => {
//<-- write your getToken() and getUserDate() here
getToken();
getUserData()
}, []);
useEffect(() => {
const getRekomendasi = async (token, bagian) => {
try {
const response = await sippApi.get(`/penjaminan?bagian=${bagian}`, {
headers: {
Auth: token
}
});
setRekomendasi(response.data.data)
console.log(rekomendasi)
} catch (error) {
console.log(error)
}
}
getRekomendasi(token, userData.bagian);
},[token,userData.bagian]);
Problem solved by using useFocusEffect
useFocusEffect(
React.useCallback(() => {
getRekomendasi(token, userData.bagian)
}, [token, userData.bagian])
);

Why does header button onPress act differently than regular button onPress?

I have a method called sendResults() that makes an API call and does some array manipulation. When I call the method using a "normal" TouchableOpacity button, everything works fine. However, when I call it using a button I have placed in the App Stack header, the method does not run correctly. It feels like an async issue (?) but not sure...
Here is the code for the two buttons.
<TouchableOpacity
onPress={() => {
sendResults(); // works fine
}}
style={styles.buttonStyle}
>
<Text>Save</Text>
</TouchableOpacity>
useEffect(() => {
navigation.setOptions({
headerRight: () => (
<TouchableOpacity
onPress={() => {
sendResults(); // doesn't work
}}
style={styles.buttonStyle}
>
<Text>Save</Text>
</TouchableOpacity>
),
});
}, []);
Edit: sendResults() code
// Shows alert confirming user wants to send results to API
const sendResults = () => {
Alert.alert("Save Results", "Alert", [
{
text: "Save & Quit",
onPress: () => postNumsAndNavigate(),
style: "destructive",
},
{ text: "Cancel", onPress: () => console.log("") },
]);
};
// Save Results button
const postNumsAndNavigate = async () => {
if (bibNums.length == 0) {
alert("You have not recorded any results. Please try again.");
} else if (bibNums.filter((entry) => entry == "").length > 0) {
alert("Blank");
} else {
console.log("\n" + bibNums);
await postNums();
AsyncStorage.setItem(`done`, "true");
navigation.navigate("Home Screen");
}
};
postNums() does an API call.
Edit 2: bibNums declaration
const [bibNums, setBibNums] = useState([]);
You set the handler of the navigation button only once because your useEffect doesn't have any dependency; it runs only when the component is mounted, it captures an old reference of sendResults. sendResults changes every time postNumsAndNavigate and bibNums change. Add sendResults to the dependency array to update the navigation button handler every time sendResults changes.
useEffect(() => {
...
}, [sendResults])
It works correctly for the TouchableOpacity because you are assigning the handler on every render.
onPress={() => {sendResults()}}

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.

React-Native; Objects are not valid as a react child

I'm getting an error at dataSource: responseJson.event_array, when I remove this line everything works fine however, when I compare it to other peoples code it's the same. It does reach the server, because I do not get the alert message.
componentDidMount() {
fetch('valid url')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
dataSource: responseJson.event_array,
isLoading: false
});
})
.catch((error) => {
alert('Could not reach the server!')
});
}
What am I doing wrong, The error is
Invariant Violation: Objects are not valid as a React child (found:
object with keys {_40,_65,_55,_72})
'valid url' points to a json file and is indeed an object, I'm trying to use the data to compare it to other data stored to use a if function which will decide whether the item of FlatList will be rendered or not
<FlatList
data={this.state.dataSource}
renderItem={this.renderItem}
keyExtractor={item => item.name}
/>
another piece of code
renderItem = async ({item}) => {
var approved = false;
var name_string = await AsyncStorage.getItem('planner_name');
if(name_string != null){
var name_array = name_string.split(',');
name_array.map(name => {
if(name == item.name){
approved = true;
}
})
}
startReading = ({item}) => {
this.setState({
reading: true,
item: item
});
}
if(approved){
return (
<TouchableOpacity style={{flex: 1, flexDirection: 'row', marginBottom: 5}} onPress={() => this.startReading({item})}>
<Text>{item.name}</Text>
</TouchableOpacity>
);
} else {
return null
}
}
If you have any question feel free to ask.
Thank you for your time.
This:
object with keys {_40,_65,_55,_72}
is an unresolved promise. I suspect the issue is that this.renderItem is an async function which I suspect is not allowed. async is essentially going to wrap the result of your function in a Promise, which then must be resolved. Since renderItem does not expect a Promise, it does not know to resolve one and as such is simply returning an unresolved Promise object for each item in your data source.
Instead you could try using an async function expression:
renderItem = ({item}) => {
const get_name_string = async function(key){
const name_string = await AsyncStorage.getItem('key')
return name_string
}
get_name_string('planner_name').then(name => {
// the rest of your renderItem function should be in this block
})
}
or simply using .then syntax on the call to AsyncStorage
renderItem = ({item}) => {
AsyncStorage.getItem('planner_name').then(name => {
// again, the rest of your function should be in this block
})
}
or better yet find another pattern that doesn't require you to use asynchronous code in your renderItem function. Hope this helps, let me know if you have any questions!

Unhandled Promise Rejection : Existing value for key "Favorites" must be of type null or array, revived string

my problem is quite simple but I'm new to react native dev. I'd like to save multiple elements with AsyncStorage (I'm using react-native-simple-store
a library that works like a wrapper but it's same logic) I want display all items for a key in a list , my code look like this:
constructor(props) {
super(props)
this.state = {
UserInput: "",
}
}
SaveValue = () => {
store.push('Favorites', this.state.UserInput)
Keyboard.dismiss()
};
FetchValue = () => {
store.get('Favorites').then((value) => {
this.setState({
favs: value
});
}).done();
};
Same thing with AsynStorage, it just update the item which is not my goal, I'd like to add a new one
SaveValue = () => {
AsyncStorage.setItem("Favorites", this.state.UserInput);
Keyboard.dismiss()
};
FetchValue = () => {
AsyncStorage.getItem("Favorites").then((value) => {
this.setState({
favs: value
});
}).done();
};
This part is my view where I try to display data, you can also see that I use a text input and two buttons one to save and the other to display an array of items stored
render() {
return (
<View>
<TextInput
onChangeText={(UserInput) => this.setState({UserInput})}
placeholder= "Type something"
value={this.state.UserInput} />
<TouchableOpacity
onPress={this.SaveValue}>
<Text>Save</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={this.FetchValue}>
<Text>Fetch</Text>
</TouchableOpacity>
<Text>{this.state.favs}</Text>
</View>
);
}
At this point I can see only one item, I tried to figure it out and saw that I have to use another method called push but when I changed save by push it throw me an error
Unhandled Promise Rejection : Existing value for key "Favorites" must be of type null or array, revived string.
Thanks!
it will work :)
renderFavorites = () => {
AsyncStorage.getItem("Favorites").then((favs) => {
favs.map((fav) => {
return (<Text> {fav} </Text>);
});
});
}
render() {
return (
<View>
<TextInput
onChangeText={(UserInput) => this.setState({UserInput})}
placeholder= "Type something"
value={this.state.UserInput} />
<TouchableOpacity
onPress={this.SaveValue}>
<Text>Save</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={this.FetchValue}>
<Text>Fetch</Text>
</TouchableOpacity>
{this.renderFavorites()}
</View>
);
}
Solution using JSON:
SaveValue = () => {
const newFavs = [...this.state.favs, this.state.UserInput];
this.setState({ favs: newFavs, UserInput: '' }, () => {
AsyncStorage.setItem("Favorites", JSON.stringify(this.state.favs));
Keyboard.dismiss()
});
};
FetchValue = () => {
AsyncStorage.getItem("Favorites").then((value) => {
this.setState({
favs: JSON.parse(value)
});
}).done();
};