React Native - Timeout on fetching - react-native

How can I set a timeout when fetching an API?
What I want exactly is to try to fetch the data for 10 seconds, if it fails then I want to load the data (saved previously and updated every time that the fetch works) from AsyncStorage.
Probably how I'm doing this is not the correct way, I'm kinda noob at programming (xD). However, this code works just fine on the emulator but does not work on my phone (android). The AsyncStorage seems not to work.
Here is my code:
constructor(){
super()
this.state = {
fetching: false,
data: []
}
}
componentWillMount(){
this.setState({ fetching: true })
fetch('http://192.168.1.122:3000/categories.json')
.then(res => res.json())
.then(res => {
this.setState({
data: res,
fetching: false
})
})
.then(res => {
AsyncStorage.setItem(
'#Data:Monumentos',
JSON.stringify(res)
)
})
.catch(AsyncStorage.getItem(
'#Data:Monuments',
(err, dados) => {
if(err) {
console.error('Error loading monuments', err)
} else {
const monuments = JSON.parse(dados)
this.setState({
data: monuments
})
}
}
))
}
Hope you can help me. Thank you!

RN uses whatwg-fetch which doesn't have a timeout. You can work around it by using whatwg-fetch-timeout as mentioned here
That would be simpler than what Micheal above in the comments linked too which is to use Promise.race and setTimeout. Admittedly, pretty clever.

Related

Unable to set useState variable in async method and console log it

Im working with my friends on a app project and we find an issue many times when we tring to set a use state and the console log the variable, i've looking for a solution in the website and saw that the reason is that the usestate is an async awiat which means the variable that i set in the use state isn't immidatly set in it, so i tried many solution that i found in the websites but none of them work for me.
in the screenShot you can see that the json variable is in console log before and the set varaible doesn't show after the setActiveUser , any help?
Thanks!
If you want to do something upon setting state then your best bet is to use the useEffect hook from React and adding your state in the dependency array. This will then call the function in your useEffect every time the state changes. See below a rough example:
import { Text } from 'react-native';
const MyComponent = () => {
const [activeUser, setActiveUser] = useState(null);
useEffect(() => {
// This should log every time activeUser changes
console.log({ activeUser });
}, [activeUser]);
const fetchAuthentication = async user => {
var flag = false;
await fetch('/api/authUser/', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(user),
})
.then(res => {
res.ok && (flag = true);
return res.json();
})
.then(json => {
if (flag) {
setActiveUser(json);
}
})
.catch(error => console.error(error));
return flag;
};
return <Text>Hi</Text>;
};
Full documentation: https://reactjs.org/docs/hooks-effect.html

AsyncStorage.removeItem is not removing the item

There are so many questions available and I have tried almost about 12 different ways but none are working. The most efficient one is:
async function removeItemValue(key) {
try {
await AsyncStorage.removeItem(key);
return true;
}
catch (exception) {
return false;
}
}
Then I'm calling it as:
useEffect(() => {
removeItemValue('#cartInfo');
}, []);
I've tried putting it outside of useEffect hook but still no effect. What am I doing wrong?
UPDATE:
Tried this as well but didn't work:
useEffect(() => {
removeItemValue('#cartInfo').then(() => { console.log('removed') })
}, []);
Also tried
useEffect(() => {
AsyncStorage.removeItem('#cartInfo', () => {
AsyncStorage.getItem('#cartInfo').then((res) => {
console.log("RES IS: " + res);
})
})
}, []);
Still no luck. I'm using v1.12.1 of #react-native-community/async-storage
As we discussed in chat, AsyncStorage.removeItem was actually working, and the issue is that setItem was being called too often, so that the value was replaced before being read later in getItem.

LayoutAnimation not working when reordering flatlist items

I'm trying to let my flatlist animate every time the order of my list gets changed. For this I tried using the LayoutAnimation API from react native. My state gets updated via redux. When I delete or add new items to the list it works completely fine but it doesn't when I try to change the sortOrder in all my items.
Code
When I finishing a workout. I log the workout which returns me the new reordered workoutList from my API.
LayoutAnimation.easeInEaseOut();
dispatch(logWorkout(inputWorkout));
navigation.navigate("WorkoutListScreen");
logWorkout
export const logWorkout = (workout: Workout) => async (
dispatch: Dispatch<WorkoutDispatchTypes>
) => {
console.log('WORKOUT_LOG_ACTION');
// dispatch({
// type: LOG_WORKOUT_LOADING,
// })
_logWorkout(workout)
.then((result: any) => {
handleNewTokenForRequest(result.headers.authorization, dispatch);
// LayoutAnimation.easeInEaseOut()
dispatch({
type: LOG_WORKOUT_SUCCESS,
payload: {
workoutList: result.data.filter(
(item: any) => item.archived === false
),
archivedWorkoutList: result.data.filter(
(item: any) => item.archived === true
),
message: lang.t('LOG_WORKOUT_SUCCESS'),
},
});
dispatch < any > getLogHistory();
})
.catch((err) => {
if (handleUnauthorizedRequest(err, dispatch)) return;
console.log(err.response);
console.log(err);
dispatch({
type: LOG_WORKOUT_FAIL,
payload: {
message: lang.t('LOG_WORKOUT_FAIL'),
},
});
});
};
Attempts
I got the sortOrder of every item as the itemĀ“s key.
KeyExtractor of the Flatlist is also using the sortOrder of the items.
My LayoutAnimation is executed before my state is updated.
I have also tried to use Transitions from react reanimated
Also added the following code to make it work for android
if (Platform.OS === 'android') {
if (UIManager.setLayoutAnimationEnabledExperimental) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
}
I don't really know what else to try.
Please let me know if you need some code or further information.
Does anybody have a tip for me? I really don't understand why it's not working.
Nobody got an idea? I still couldn't fix the problem.

React-native useEffect hook refresh fetch

I'm trying to build a react-native weather app, fetching data from the openweather api using hooks like this:
useEffect(() => {
async function fetchWeather() {
try {
let data = await fetch(URL);
const json = await data.json();
dispatch({type: 'success', payload: json});
} catch (error) {
dispatch({type: 'failure'});
}
}
fetchWeather();
}, []);
This only loads the data once. I want to make sure the weather info stays up to date. What is the best way to refresh the data? Do I poll every X minutes (if so how)?
Are you looking for a period of time, you will call api?
try it:
const [isStatus, setStatus] = useState(true)
setInterval(()=> {
setStatus(!isStatus)
}, 3000)
useEffect(() => {
fetchWeather();
}, [isStatus])
or you only can use this function:
useEffect(() => {
let loop = setInterval(()=> {
fetchWeather();
}, 3000);
return () => clearInterval(loop);
}, [])
My example applies when the application is opening

React-Native using nested async not working properly

I have methods that benefit each other and I want one of them to start after the other, but it doesn't work exactly the way I want it. In another question, I used async and await in a normal method, but I did not manage to use google APIS and nested functions.
async componentDidMount() {
await this.getCityList();
console.log(this.state.cities)
await this.currentLocation();
await this.getVenueInformation();
}
At this point, the first function works correctly and after passing the required ones, it goes to the 2nd method. In the same way, I have to put the inputs of the 2nd method into the 3rd method, but I failed.
Current location method:
currentLocation() {
Geocoder.init(...);
Geolocation.getCurrentPosition((position) => {
this.getCurrentLoc(position.coords.latitude, position.coords.longitude),
this.setState({
region: {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
},
error: null,
});
}, (error) => this.setState({ error: error.message }), { enableHighAccuracy: false, timeout: 200000, maximumAge: 1000 });
}
I want my location with the above method, then I get the address information with getcurrentloc method and I plan to show some places in the vicinity in accordance with that information. However, I could not make this system work sequentially and my address is always null.
getCurrentLoc(lat, longt) {
Geocoder.from(lat, longt)
.then(json => {....
this.setState({...},
this.getLocIDS(cityName, districtName, neighborhoodName)
);
})
.catch(error => console.warn(error));
}
at this point, I get the address from the database by address to pull the id information.
getLocIDS(cityName, districtName, neighborhoodName) {
let link = ..;
fetch(link)
.then(response => response.json())
.then(res => {
this.setState({,,,,,,})
})
.catch(error => console.warn(error));
}
lastly, I want to capture the venue information, but at this point the data is entered as -1 in the database. -1 is my initial state value. I'm sure all methods work correctly, but since the processes don't run sequentially, my space search method works before updating the data in the previous functions state.
getVenueInformation() {
let link = ...
fetch(link)
.then(response => response.json())
.then(venues => {
this.setState({
markers: venues,
isLoading: false,
})
})
};
database input return: >>>>> SELECT * FROM mekanlar WHERE mekanlar.mahalle_no="-1";
You don't show how you pass the information from one method to the other.
If you do it by use of this.state, that is where your problem is.
this.setState will not update the state synchronously. So you might not have the right value in this.state in your next function call.
To make sure the data flow is correct, it makes more sense to return the values explicitly, even if you do setState internally.
async componentDidMount() {
const cityList = await this.getCityList();
console.log(cityList)
const location = await this.currentLocation(cityList);
const venueInformation = await this.getVenueInformation(location);
}