React Native Possible Unhandled Promise Error with axios - react-native

I am trying to fetch two different api with axios and use it on different flatlist
I'm getting this error:
[Unhandled promise rejection: Error: Request failed with status code 429]
Possible Unhandled Promise Rejection (id: 28)
Here's the my code
const [data, setData] = React.useState([]);
const [data1, setData1] = React.useState([]);
axios.all([
axios.get('https://jsonplaceholder.typicode.com/nation'),
axios.get('https://jsonplaceholder.typicode.com/state')
])
.then(responseArr => {
setData(responseArr[0].data);
setData1(responseArr[1].data);
});
return (
<View style={styles.container}>
<View >
<FlatList
data={data}
listKey="nation"
keyExtractor={item => item.id}
showsVerticalScrollIndicator = {false}
renderItem={({item}) => {
return (
<View>
<Text>{item.event_id}</Text>
</View>
)
}}
/>
</View>
<View style={{ marginTop: 30 }}>
<FlatList
data={data1}
listKey="state"
keyExtractor={item => item.id}
showsVerticalScrollIndicator = {false}
renderItem={({item}) => {
return (
<View>
<Text>{item.venue_id}</Text>
</View>
)
}}
/>
</View>
</View>
);
};
Thank for your help

You are receiving a HTTP 429 error code which means:
The HTTP 429 Too Many Requests response status code indicates the user has sent too many requests in a given amount of time ("rate limiting").
You are calling the API too many times, what's happening is:
axios is called.
setData() is executed and your state variable updates.
The rerender is causing axios to run again.
Congratulations, you're now in a loop!
Refactor your code to only run the API call at appropriate times. Something like this:
useEffect(() => {
axios.all([
axios.get('https://jsonplaceholder.typicode.com/nation'),
axios.get('https://jsonplaceholder.typicode.com/state')
])
.then(responseArr => {
setData(responseArr[0].data);
setData1(responseArr[1].data);
});
}, []); // Ensure any dependencies are added here.
For good measure you should also handle the rejection, which is what the original error is mentioning.
axios.all().then().catch() - You're missing a catch statement.
For the question in the comments, you need to use back ticks when interpolating strings.
<Image
source={{
uri: `https://jsonplaceholder.typicode.com/nation/image/${item.nation_image}`
}}
/>

Related

Could not find "client" in the context or passed in as an option. Wrap the root component in an <ApolloProvider>, or pass an ApolloClient instance

This is my first Apollo Project, but I have been working with it for awhile, and things had been pretty smooth in terms of Apollo, until recently.
While I understand how Apollo works, I obviously do not know all the minutae involved with it, and I am unclear I suppose on exactly how the project is supposed to be wrapped.
Below is my App.js, when it worked as anticipated...
// Auth for token
const authLink = setContext((_, { headers }) => {
const token = state
return {
headers: {
...headers,
authorization: token ? `${token}` : ''
}
}
})
// Initialize Apollo Client
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
});
const Stack = createNativeStackNavigator();
export default function App() {
// Other irrelevant things like fonts...
const ErrorPrompt = (props) => {
return(
<View>
<View style={{height: 50, width: '100%', backgroundColor: "#534FFF"}}/>
<Text style={{...Template.title, fontSize: 30}}>Something happened!</Text>
<Text style={{...Template.subTitle, fontSize: 20}}>We apologize for the inconvenience</Text>
<Text style={{...Template.title, fontSize: 20, color: '#534FFF'}}>{props.error.toString()}</Text>
<View style={{marginLeft: 30}}>
<Text style={{...Template.subTitle, fontSize: 15, marginRight: 30, marginLeft: 0}}>An email has been sent to the Support Team to attempt to prevent this error from occurring again. We thank you for your support and patience</Text>
</View>
<View style={{marginTop: 50}}>
<Button onPress={props.resetError} title={'Reload Application'} />
</View>
</View>
)
}
if(!loaded){
return null
}
try{
return (
<ErrorBoundary
FallbackComponent={ErrorPrompt}
>
<NavigationContainer>
<ApolloProvider client={client}>
<RecoilRoot>
<IconRegistry icons={EvaIconsPack} />
<ApplicationProvider {...eva} theme={{...eva.light, ...theme}}>
<PaperProvider>
<KeyboardAvoidingView
behavior="padding"
enabled
style={{flexGrow:1,height:'110%'}}
>
<View style={AppStyles.container}>
<Stack.Navigator screenOptions={{headerShown: false}}>
{/* {loggedIn === false ? ( */}
<Stack.Screen name="/">
{props => <LandingPage {...props} handleLoggedIn={handleLoggedIn} rememberMe={rememberMe} setRememberMe={setRememberMe} />}
</Stack.Screen>
{/* ) : null} */}
<Stack.Screen name="home">
{props => <Home {...props} handleLoggedIn={handleLoggedIn} />}
</Stack.Screen>
{/* About 40 more Stack Screens */}
</Stack.Navigator>
</View>
</KeyboardAvoidingView>
</PaperProvider>
</ApplicationProvider>
</RecoilRoot>
</ApolloProvider>
</NavigationContainer>
</ErrorBoundary>
)
}
catch(error){
return(<ErrorPrompt code={error} />)
}
I apologize for the amount of code, but my primary question is, does the order of the wrapping components matter? I know I need my NavContainer, ErrorBoundary, and RecoilRoot wrapping all of the pages, but do the orders of these matter? Because the code I have about was working perfectly until I added a mutation to the ErrorPrompt Component. The new ErrorPrompt looked like this...
const ErrorPrompt = (props) => {
useEffect(() => {
sendErrorEmail({
variables: {
errorCode: props.error.toString()
}
})
}, [])
return(
// The same return as before
)
}
After this addition, I was given the Could not find "client" in the context or passed in as an option. Wrap the root component in an <ApolloProvider>, or pass an ApolloClient instance error. The message isn't particularly helpful, as both everything is wrapped in AND I have a client passed in. Does anyone know the solution / if order of these wrappings matters, and it it does, what order it should be in?
I found the issue. It was not a matter of the order in which things were wrapped but rather that I had the declaration for the sendErrorEmail mutation OUTSIDE of a component that was wrapped with the Apollo Provider. I had it out floating in App.js, but when I moved the line to under ErrorPrompt = () => { the error was removed

Can't figure out why React Hook is invalid

I'm trying to use useContext hook in a React Native page I have, I'm using this hook in other components as well and they work just fine, but this one won't - can't figure out why.
This is my component:
const GoalCard = (goal: IGoal) => {
const {theme} = useContext(ThemeContext); <-- error is here
return (
<Animated.View style={[styles.card, {height: cardHeight, backgroundColor: "#ff5e"}]}>
<View>
.....
</View>
</Animated.View>
);
I'm using this component inside a FlatList which is in a separate file.
return (
<SafeAreaView style={[styles.pageContainer, {backgroundColor: theme.background}]}>
<FlatList
showsVerticalScrollIndicator={false}
style={{padding: 8}}
data={goals}
renderItem={({index}) => GoalCard(goals[index])}
keyExtractor={item => item.id}
/>
</SafeAreaView>
);
I get the error: Invalid hook call, but it does not seem like something is wrong here.
Saw few questions about this, but none worked, also, nothing seems wrong according to the Rules of Hooks page. Why this error happens here?
EDIT:
this is my ThemeProvider:
function ThemeProvider({ children }) {
const [dark, setDark] = React.useState(false);
const toggle = () => {
setDark(!dark);
}
const theme = dark ? themes.dark : themes.light;
return (
<ThemeContext.Provider value={{theme, dark, toggle}}>
{children}
</ThemeContext.Provider>
)
}
And this is my App.tsx:
<ThemeProvider>
<Provider store={store}>
<NavigationContainer>
.....
</NavigationContainer>
</Provider>
</ThemeProvider>

useEffect not working in custom drawer component without refresh

So I am using react-navigation 5 and I have a custom drawer component for my app. I want to display the name of the logged-in user in the drawer for which I am using a state variable and I am updating the state from firestore. I am calling a function in useEffect which accesses firestore and gets the name of the user. But I think the useEffect is not working without refresh because unless I save the project and refresh the application the state is not getting updated in the application and I cannot see the name of the user without refreshing but it is visible after a refresh. Any ideas why this is happening? Any help would be appreciated. Thank you.
Custom drawer
export default function CustomDrawer(props) {
const paperTheme = useTheme();
const [name,setName]=useState('');
useEffect(() => {
doStuff();
}, []);
const doStuff = async () => {
var phone=global.phone;
await firestore().collection("Users").where('Phone Number', '==', phone).get().then(querySnapshot=>{
querySnapshot.forEach(documentSnapshot => {
console.log("in drawer");
console.log(documentSnapshot.data());
setName(documentSnapshot.data().Name);
})
})
};
return(
<View style={{flex:1}}>
<DrawerContentScrollView {...props}>
<View style={styles.drawerContent}>
<View style={styles.userInfoSection}>
<View style={{flexDirection:'row',marginTop: 15}}>
<Avatar.Image
source={{
uri: ''
}}
size={50}
/>
<View style={{marginLeft:15, flexDirection:'column'}}>
<Title style={styles.title}>{name}</Title>
</View>
</View>
</View>
</View>
</DrawerContentScrollView>
</View>
);
}
Looks like you have doStuff function defined outside the useEffects.
Either you need to put it inside useEffects or add it in dependency list
useEffect(() => {
doStuff();
}, [doStuff]);

FlatList's renderItem doesn't recognise "this" keyword

So, I recently started making FlatList a recurring thing in the app I'm working on. I am right now working on a screen that gives a list of requests and is updated once one is accepted, which is done by pressing a button. There's a method called getNewRequests I am using to update the requests, but it can't seem to be called by the flatline, as it only returns the error TypeError: _this3 is undefined.
I really need that method to work, because I need to update the state of that screen, and trying to type the whole method there only returns the same error. In that context, this always returns undefined.
render(){
return(
<View style={GenericStyles.styles.genericContainer}>
<Text> REQUEST SCREEN </Text>
<FlatList
data={this.state.requestList}
renderItem={this.renderItem}
keyExtractor={item => item.id}
/>
<Button title="Voltar" color="cyan" onPress={() => this.props.navigation.goBack()}/>
</View>
);
}
renderItem({item}){
return(
<Card
containerStyle={{flex: 1, width: 200}}
title={item.Username}>
<Button color="blue" title="Accept" onPress={() => RequestService.allowRequest(item.id, (response) => {
let rsp = JSON.parse(response);
if(rsp.success){
this.getNewRequests();
}
})}/>
</Card>
);
}
You need to either bind the function in your constructor (or wherever you want) doing:
constructor(props){
super(props)
this.renderItem.bind(this)
}
or use arrow function:
renderItem = ({item}) => {
//your function
}
Doing this will give the function access to the this of the current component.

Trying to connect to api with link stored in two components

I'm trying to fetch data from API, using the link combined from link fetched from another component and API token, but the API is not returning anything.
I suspect the connection to API might be correct and the issue lies with wrongly fetching specific objects from the API structure. api structure
componentDidMount(){
const { navigation } = this.props;
const linkPlant = navigation.getParam('linkPlant');
fetch(linkPlant + '?token=/////FY03yEVzS77Ca1Q9TIbMdMlJhXtpOjhcqcD-MJHA')
.then(response => response.json())
.then((responseJson)=> {
this.setState({
loading: false,
dataSource: responseJson
})
})
.catch(error=>console.log(error))
}
renderItem=(data)=>
<TouchableOpacity style={styles.list}>
<Text style={styles.lightText}>{data.item.varieties[0].common_name}</Text>
</TouchableOpacity>
render(){
return(
<View>
<FlatList
data= {this.state.dataSource}
renderItem= {item=> this.renderItem(item)}
keyExtractor= {item=>item.id.toString()} />
</View>
</ScrollView>
);}
{!loading?
<View>
<FlatList
data= {this.state.dataSource}
renderItem= {item=> this.renderItem(item)}
keyExtractor= {item=>item.id.toString()} />
</View>
: <View><Text>Loading</Text></View>}
You've defined an loading promise but never used that. Maybe using it for render when page is loaded could be fix that error.