Fetching Data as a Json format in react native return error when mapping data - react-native

The error returned is : undefined is not an object (evaluating 'json.map') ,knowing that my api has multiple data.
The code i use to fetch data is :
CheckifReadLater = async () => {
const username = await AsyncStorage.getItem('username');
const isLoggedIn = await AsyncStorage.getItem('isLoggedIn');
if (isLoggedIn == 1 && username) {
await fetch(Config.backendAPI+`/readlater.php?username=${username}&select`)
.then((response) => {
reactotron.log("Response : ",response);
response.json();
})
.then((json) => {
json.map((product, index) => {
if (product.id == this.props.product.id) {
this.setState({
isReadLater: true,
})
}
});
})
.catch((error) => reactotron.log('This is the error: ',error))
}
reactotron.log("Readlater : ",this.state.isReadLater);
}
How can i solve this problem ?

You should return the response.json(); on the first .then function for it to be available on the next .then.
Do this:
await fetch(Config.backendAPI+`/readlater.php?username=${username}&select`)
.then((response) => {
reactotron.log("Response : ",response);
// update your code here
return response.json();
})

Related

Setting data from firebase with useState is returning undefined

I am trying to set data for verification purposes. I do set the data then get undefined which is disturbing to me, I've tried to parse it in different shapes, I've used useCallback hook and without any real benefit
const getUserPhone = useCallback(async () => {
console.log('user phone is requested');
await firebase
.database()
.ref(`users/${login.uid}`)
.once(
'value',
async (data) => {
if (data.exists()) {
console.log('found');
await setUserData(data.toJSON());
console.log('data has been set');
} else {
Alert.alert('User not found');
return;
}
},
// I've tried .get() from firebase and
//.then(async (data: IUser) => {await setUserData(data.toJSON()})
// It does the same.
)
.catch((error) => {
return console.error(error);
});
}, [login.uid]);
const handleVerification = useCallback(async () => {
if (alreadyRequested) {
return;
}
await getUserPhone();
try {
console.log(userData); // undefined
if (!userData?.phoneNumber) {
console.log('no phone number is here');
return;
}
...
} catch ...
}, [alreadyRequested, getUserData, userData?.phoneNumber])
Output:
user phone is requested
found
data has been set
undefined
no phone number is here

React-native-fetch-blob GET request error

I am replacing axios to rn-fetch-blob in my react-native project. In the request I ping my server with credentials and I expect a response.
The old request with axios is as follows and works perfectly:
export const postWorkspace =
(newWorkspace: Workspace): AppThunk =>
async (dispatch) => {
console.log('addWorkspace Start');
dispatch(setIsLoading(true));
let configOption = {
headers: {
'Access-Control-Allow-Origin': '*',
'X-AUTH-USER': newWorkspace.credentials.email,
'X-AUTH-TOKEN': newWorkspace.credentials.password,
},
};
await axios
.get(`${newWorkspace.url}/api/ping`, configOption)
.then(async (resp) => {
console.log('addWorkspace resp', resp);
try {
await storeWorkspaceToStorage(newWorkspace);
} catch (e) {
console.error(e);
}
})
.catch((err) => {
console.log('addWorkspace err', JSON.stringify(err));
return Promise.reject(err);
})
.finally(() => dispatch(setIsLoading(false)));
};
This is how I transformed the code with rn-fetch-blob:
export const postWorkspace=
(newWorkspace: Workspace): AppThunk =>
async (dispatch) => {
console.log('addWorkspace Start');
dispatch(setIsLoading(true));
let configOption = {
'Access-Control-Allow-Origin': '*',
'X-AUTH-USER': newWorkspace.credentials.email,
'X-AUTH-TOKEN': newWorkspace.credentials.password,
};
await RNFetchBlob
.fetch('GET', '${newWorkspace.url}/api/ping', configOption)
.then( async(resp) => {
console.log('addWorkspace resp', resp);
try {
await storeWorkspaceToStorage(newWorkspace);
} catch (e) {
console.error(e);
}
})
.catch((err) => {
//console.log(err.info().status);
console.log('addWorkspace err', JSON.stringify(err));
return Promise.reject(err);
})
.finally(() => dispatch(setIsLoading(false)));
};
The new request with rn-fetch-blob returns this error:
response error "line":126349,"column":34,"sourceURL":"http://localhost:8081/index.bundle?platform=android&dev=true&minify=false"
When I opend the file "http://localhost:8081/index.bundle?platform=android&dev=true&minify=false" around line 1262349 the code looks like this, I can't understand what went wrong:
var req = RNFetchBlob[nativeMethodName];
req(options, taskId, method, url, headers || {}, body, function (err, rawType, data) {
subscription.remove();
subscriptionUpload.remove();
stateEvent.remove();
partEvent.remove();
delete promise['progress'];
delete promise['uploadProgress'];
delete promise['stateChange'];
delete promise['part'];
delete promise['cancel'];
promise.cancel = function () {};
//line 126349
if (err) reject(new Error(err, respInfo));else {
if (options.path || options.fileCache || options.addAndroidDownloads || options.key || options.auto && respInfo.respType === 'blob') {
if (options.session) session(options.session).add(data);
}
respInfo.rnfbEncode = rawType;
resolve(new FetchBlobResponse(taskId, respInfo, data));
}
});
});
I am doing this since rn-fetch-blob is basically one of the few libraries that allows react-native to ping a server with no SSL certification.
Thank you

Can't perform a React state update on an unmounted component. useEffect Hook

I seem to be missing something subtle about avoiding memory leaks. I have read a few posts on how to avoid this with async functions and have tried a few things. All seem to fail. Could someone point out what I'm doing wrong.
useEffect(() => {
let ignore = false;
if (Platform.OS === "android" && !Constants.isDevice) {
errorMessage("Oops, this will not work on Sketch in an Android emulator. Try it on your device!");
} else {
// function to get location, weather and aurora info
const getDataAsync = async () => {
let { status } = await Permissions.askAsync(Permissions.LOCATION);
if (status !== "granted") {
setErrorMessage("Permission to access location was denied");
}
if (!ignore) {
let location = await Location.getCurrentPositionAsync({});
// do stuff with the location data, putting it into states
fetch(`http://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${long}&APPID=${API_KEY}&units=metric`)
.then(res => res.json())
.then(json => {
// do all sorts of stuff with the weather json, putting it into states
});
// Fetch the aurora data
const myUTC = new Date().getTimezoneOffset();
fetch(`http://api.auroras.live/v1/?type=ace&data=bz&tz=${myUTC}&colour=hex`)
.then(res => res.json())
.then(json => {
// do stuff with the aurora json, put it into states
});
setIsLoaded(true); // this is for the activity indicator
}
}
getDataAsync();
return () => { ignore = true; }
}
}, []);
I'm getting the error when deliberately quickly switching out of the screen and back again while the activity indicator is spinning.
Return the cleanup outside of everything! let me know if it works
useEffect(() => {
let ignore = false;
if (Platform.OS === 'android' && !Constants.isDevice) {
errorMessage(
'Oops, this will not work on Sketch in an Android emulator. Try it on your device!',
);
} else {
// function to get location, weather and aurora info
const getDataAsync = async () => {
let {status} = await Permissions.askAsync(Permissions.LOCATION);
if (status !== 'granted') {
setErrorMessage('Permission to access location was denied');
}
if (!ignore) {
let location = await Location.getCurrentPositionAsync({});
// do stuff with the location data, putting it into states
fetch(
`http://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${long}&APPID=${API_KEY}&units=metric`,
)
.then((res) => res.json())
.then((json) => {
// do all sorts of stuff with the weather json, putting it into states
});
// Fetch the aurora data
const myUTC = new Date().getTimezoneOffset();
fetch(
`http://api.auroras.live/v1/?type=ace&data=bz&tz=${myUTC}&colour=hex`,
)
.then((res) => res.json())
.then((json) => {
// do stuff with the aurora json, put it into states
});
setIsLoaded(true); // this is for the activity indicator
}
};
getDataAsync();
}
return () => {
ignore = true;
};
}, []);
That was promising, but no, it didn't work. It may have to do with the fact that there are 2 async fetch requests and one "await" location request with each taking a different amount of time.
I am trying with abortController but that isn't working either:
useEffect(() => {
const abortController = new AbortController();
if (Platform.OS === 'android' && !Constants.isDevice) {
errorMessage(
'Oops, this will not work on Sketch in an Android emulator. Try it on your device!',
);
} else {
// function to get location, weather and aurora info
const getDataAsync = async () => {
let {status} = await Permissions.askAsync(Permissions.LOCATION);
if (status !== 'granted') {
setErrorMessage('Permission to access location was denied');
}
let location = await Location.getCurrentPositionAsync({signal: abortController.signal});
// do stuff with the location data, putting it into states
fetch(
`http://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${long}&APPID=${API_KEY}&units=metric`, { signal: abortController.signal })
.then((res) => res.json())
.then((json) => {
// do all sorts of stuff with the weather json, putting it into states
});
// Fetch the aurora data
const myUTC = new Date().getTimezoneOffset();
fetch(
`http://api.auroras.live/v1/?type=ace&data=bz&tz=${myUTC}&colour=hex`, { signal: abortController.signal })
.then((res) => res.json())
.then((json) => {
// do stuff with the aurora json, put it into states
});
setIsLoaded(true); // this is for the activity indicator
};
getDataAsync();
}
return () => {
abortController.abort();
}
}, []);
In addition to the memory leak error in the console, I am also getting:
Possible Unhandled Promise Rejection (id: 0):
[AbortError: Aborted]
Possible Unhandled Promise Rejection (id: 1):
[AbortError: Aborted]

Store the result of an async function into a variable

I am trying to store the result of an async function into a variable,but the output of my code didn't seems to be the expected one. What am I doing wrong ?
async function get_happy_songs() {
let urlOfS = 'http://10.0.2.2:5000/happy_songs'
try {
let response = await fetch(
urlOfS, {
method: 'GET'
}
);
let json = await response.json();
//console.log(json.melodies);
return json.melodies;
} catch (error) {
console.error(error);
}
}
//var happy_songs = [];
let happy_songs = get_happy_songs();
console.log(happy_songs)
Try like this.
async function get_happy_songs() {
let urlOfS = 'http://10.0.2.2:5000/happy_songs'
return fetch(urlOfS, {
method: 'GET'
}).then((response) => response.json())
.then((responseJson) => {
console.log('response object:', responseJson)
return responseJson;
})
.catch((error) => {
console.error(error);
});
}
let happy_songs = await get_happy_songs();
console.log(happy_songs)

Send single response after multiple updates

I have an array of items that I am passing to an API endpoint (using Sequelize as my ORM). I'm trying to iterate over each item and update it, however I'm getting a Unhandled rejection Error: Can't set headers after they are sent.
stepsController.put = (req, res) => {
const { steps } = req.body;
// Steps is an array of objects that I want to update...
steps.map(step => {
Step.findOne({ where: { id: step.id } })
.then(savedStep =>
savedStep
.update({
order: step.order,
})
.then(success => res.status(200).send(success))
.catch(error => res.send(error))
)
.then(ok => res.status(200).send(ok))
.catch(err => res.send(err));
});
};
I believe this is because it's sending the response for each item. Sequelize's update method is a promise. How can I iterate over all of the items and make sure all of the items are updated before sending a single successful response?
There are three ways you can do
Promise.all
Co
Async Await
1) Here it is , you can use Promise.all :
stepsController.put = (req, res) => {
const { steps } = req.body;
// Steps is an array of objects that I want to update...
Promise.all(steps.map(step => {
return Step.findOne({ where: { id: step.id } }).then(savedStep =>
return savedStep.update({
order: step.order,
})
.catch(error => error)
).catch(err => err)
}))
.then(ok => res.status(200).send(ok))
.catch(err => res.send(err));
};
2) Another way is to use co :
const co = require('co');
stepsController.put = co.wrap(function* (req, res) => {
try {
const { steps } = req.body;
// Steps is an array of objects that I want to update...
for(let i=0;i<steps.length ; i++) {
let savedStep = yield Step.findOne({ where: { id: steps[i].id } });
if(savedStep)
yield savedStep.update({ order: steps[i].order});
}
res.status(200).send();
}
catch(err){
res.send(err);
}
});
3) If you’re using Node 8.0+ , there is no need of any package you can directly use async await :
stepsController.put = async(req, res) => {
try {
const { steps } = req.body;
// Steps is an array of objects that I want to update...
for(let i=0;i<steps.length ; i++) {
let savedStep = await Step.findOne({ where: { id: steps[i].id } });
if(savedStep)
await savedStep.update({ order: steps[i].order});
}
res.status(200).send();
}
catch(err){
res.send(err);
}
};