Calling axios request one after the other? - reactjs

I have tow functions in my ReactJs application called,
AuthService.addUser(newUser);
AuthService.userCategories(usercategories);
I want to run these two functions separately, which means the Axios request of the second function should be called after the Axios request of the first function when clicked the submit button. How do I approach the solution? Thanks in advance.
I tried in this way. Is this correct?
const handleSubmit = (e) => {
e.preventDefault();
AuthService.addUser(newUser);
AuthService.userCategories(usercategories);
};
Here are my two functions
addUser: (user) => {
//console.log(post);
axios
.post(CONSTANTS.HOSTNAME + "/api/users/register", user)
.then((res) => {
//save to local storage
const { token } = res.data;
localStorage.setItem("jwtToken", token);
isAuthenticated.next(true);
setAuthToken(token);
Swal.fire({
icon: "success",
title: "Signup Successful!",
showConfirmButton: false,
timer: 1500,
}).then(() => {
window.location.href = "/";
//decode token to get user data
const decoded = jwt_decode(token);
currentUser.next(decoded);
console.log(decoded);
});
})
.catch((err) => {
console.log(err.response.data);
Swal.fire({
icon: "error",
title: "Oops...",
text: err.response.data,
});
// alert(JSON.stringify(err.response.data));
});
},
userCategories: (userCategories) => {
axios
.post(CONSTANTS.HOSTNAME + "/api/users/usercategories", userCategories)
.then((res) => {
console.log(res.data);
});
},

just use promise if function return promise:
const handleSubmit = async (e) => {
e.preventDefault();
await AuthService.addUser();
await AuthService.userCategories();
};
or make promise from function and run async
function one() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('resolve one')
return resolve("i am after five seconds")
},
2000);
});
}
function two() {
return new Promise((resolve, reject) => {
console.log('resolve two')
return resolve("i am after three seconds")
});
}
const handleSubmit = async () => {
console.log('run handleSubmit')
await one();
await two();
}
handleSubmit()

Related

Updating profile picture in firebase

i'm not sure what i'm doing wrong here, i upload a new picture to firebase storage, then i retrieve it with getDownloadUrl, and then i update the user profile photoURL, but for some reason it's not working.
const imgPath = ref(storage, "images/");
const imgUpload = () => {
if (uImg == null) return;
const imgRef = ref(storage, `images/${uImg.name + v4()}`);
uploadBytes(imgRef, uImg).then(() => {
listAll(imgPath).then((response) => {
response.items.forEach((item) => {
getDownloadURL(item).then((url) => {
setImgUrl([url]);
updateProfile(auth.currentUser, {
photoURL: `${imgUrl[0]}`,
})
.then(() => {
setProfileImg(auth.currentUser.photoURL);
console.log("success");
})
.catch((error) => {
console.log(error);
});
});
});
});
});
};
uImg is the uploaded img
It is unlikely the current user is updated by the time the updateProfile then statement runs.
Instead update the useState hook as with the imgUrl[0].
updateProfile(auth.currentUser, { photoURL: `${imgUrl[0]}` })
.then(() => {
setProfileImg(imgUrl[0]);
console.log("success");
}).catch((error) => { console.log(error); });
If you want to verify that the profile image was updated print of the value:
const auth = getAuth();
useEffect(() => {
console.log("Profile:", auth.currentUser?.photoURL);
}, []);

Wait for get request response before continuing with a post request in axios

I have tried to use async/await in the createSwap function but it did not work for me. Before creating a request, I want to run the getSlotDetails function to set the slotDets so that it can be used in the post request below. However, the createSwap function does not wait for the getSlotDetails function to complete before sending the post request. How do I fix this?
const [slotDets, setSlotDets] = useState([]);
const getSlotDetails = (moduleCode, slotId, slotType) => {
axios
.get(`https://api.nusmods.com/v2/2020-2021/modules/${moduleCode}.json`)
.then((response) => response.data)
.then((data) => data.semesterData[0])
.then((semesterData) => semesterData.timetable)
.then((timetable) =>
timetable.filter(
(slot) => slot.classNo === slotId && slot.lessonType == slotType
)
)
.then((result) => {
setSlotDets(result);
});
};
const createSwap = (
moduleCode,
slotType,
currentSlot,
desiredSlots,
completed,
reserved
) => {
dispatch(createRequest());
getSlotDetails(moduleCode, currentSlot, slotType);
axios
.post(
"http://localhost:3001/api/v1/swaps",
{
module_code: moduleCode,
slot_type: slotType,
current_slot: currentSlot,
desired_slots: desiredSlots,
completed: completed,
reserved: reserved,
venue: slotDets.venue,
startTime: slotDets.startTime,
endTime: slotDets.endTime,
day: slotDets.day,
},
{
headers,
}
)
.then((response) => {
console.log(response.data);
dispatch(createSuccess());
setTimeout(() => {
dispatch(resetSwap());
}, 2000);
})
.catch((error) => {
console.log(error.response.data);
dispatch(createFail(error.response.data));
setTimeout(() => {
dispatch(resetSwap());
}, 2000);
});
};
const makeTwoRequests = async () => {
try{
const firstResponse = await axios.get(FIRST_URL);
if(firstResponse.status === 200){
const firstResponseData = firstResponse.data;
const secondResponse = await axios.get(SECOND_URL);
if(secondResponse.status === 200){
const secondResponseData = secondResponse.data;
}
}
}
catch(error){
console.log(error)
}
}
maketwoRequests()
firstResponseData and secondResponseData can be state variables instead of const for better access throughout the Component

How to test custom hooks with event listener inside useEffect?

I'm using react native and jest to create my tests. I'm facing problems to test an event listener that listens to url events from expo-linking. This event listenner is inside an useEffect hook.
Below is the code from my custom hook with my useEffect and an event listener inside:
useEffect(() => {
isMounted.current = true;
Linking.addEventListener('url', async () => {
try {
if (!navigation.isFocused() || !isMounted.current) return;
setIsLoading(true);
const response = await api.get('sessions/auth/success');
if (!response.data) return;
console.log('aqui');
const { notRegisteredUser, token } = response.data;
api.defaults.headers.authorization = `Bearer ${token}`;
if (notRegisteredUser && token) {
setIsLoading(false);
navigation.navigate('BirthDateScreen');
dispatch(
updateUser({
...notRegisteredUser,
}),
);
}
} catch (err) {
Alert.alert('Error', `${translate('loginRegisterError')}: `, err);
}
});
return () => {
isMounted.current = false;
};
}, [dispatch, navigation]);
In my test file I have the following mocks:
jest.mock('expo-linking', () => {
return {
addEventListener: (event: string, callback: () => void) => callback(),
};
});
jest.mock('#react-navigation/native', () => {
return {
useNavigation: () => ({
isFocused: mockedNavigationFocus,
navigate: mockedNavigation,
}),
};
});
jest.mock('react-redux', () => {
return {
useDispatch: jest.fn(),
};
});
jest.mock('../../../store/modules/user/actions', () => {
return {
updateUser: jest.fn(),
};
});
jest.mock('i18n-js', () => {
return {
locale: 'en',
t: () => 'any key',
};
});
Finally this is how my test looks in my first try:
it('should pass the test', async done => {
mockedNavigationFocus.mockImplementation(() => true);
apiMock.onGet('sessions/auth/success').reply(200, {
notRegisteredUser: { name: 'Logan' },
token: '123',
});
render(<LoginScreen />);
await waitFor(() =>
expect(mockedNavigation).toHaveBeenCalledWith('BirthDateScreen'),
);
done();
});
In my second try this is how my test looked (I used renderHooks from #testing-library/react-hooks):
it('should pass the test', async () => {
mockedNavigationFocus.mockImplementation(() => true);
apiMock.onGet('sessions/auth/success').reply(200, {
notRegisteredUser: { name: 'Logan' },
token: '123',
});
const { result, waitForValueToChange } = renderHook(() => useLoginButton());
const { isLoading } = result.current;
await waitForValueToChange(() => isLoading);
await waitForValueToChange(() => isLoading);
expect(mockedNavigation).toHaveBeenCalledWith('BirthDateScreen');
});
With both tests I get the following error:
test error
Another error I get is that my callback function inside useEffect runs many times before it stops and this does not happen when I am not testing.
Does anyone knows how can I write this test?

How to make Async Await Function in React Native?

I want to create a function that is about uploading photo to Firebase Storage with react-native-fetch-blob. I'm using Redux and you can find action functions below:
My problem is that uploadImage function is not running like asynchronous. Firebase function is running before uploadImage, so application give me an error.
I think i can't make a asynchronous function. How can i fix it ?
uploadImage() function:
const uploadImage = async (imageSource, whereToUpload) => {
let imageURL = '';
const mime = 'image/jpg';
const { Blob } = RNFetchBlob.polyfill;
const { fs } = RNFetchBlob;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
console.log('URI =>', imageSource.uri);
let imgUri = imageSource.uri;
let uploadBlob = null;
const imageRef = firebase.storage().ref(whereToUpload + '/' + imageSource.fileName);
const uploadUri = Platform.OS === 'ios' ? imgUri.replace('file://', '') : imgUri;
await fs.readFile(uploadUri, 'base64')
.then((data) => Blob.build(data, { type: `${mime};BASE64` }))
.then((blob) => {
uploadBlob = blob;
return imageRef.put(blob, { contentType: mime });
})
.then(() => {
uploadBlob.close();
// eslint-disable-next-line no-return-assign
return imageURL = imageRef.getDownloadURL();
})
.catch((error) => {
console.log(error);
});
return imageURL;
};
and the main action is:
export const addProjectGroup = (
myUser,
groupName,
groupDescription,
groupProfilePic,
) => dispatch => {
const groupProfileFinalPic = async () => {
let finalGroupPicture = { landscape: '' };
if (_.isEmpty(groupProfilePic.src)) {
await uploadImage(groupProfilePic, 'groupPictures').then((imageURL) => {
console.log('İŞLEM TAMAM!');
console.log('SELECTED IMAGE URL =>', imageURL);
finalGroupPicture.landscape = imageURL;
});
} else {
finalGroupPicture.landscape = groupProfilePic.src.landscape;
}
return finalGroupPicture;
};
console.log("final group profile pic =>", groupProfileFinalPic());
// Önce grubu yaratalım..
// eslint-disable-next-line prefer-destructuring
const key = firebase
.database()
.ref()
.child('groups')
.push().key;
firebase
.database()
.ref('/groups/' + key)
.set({
admin: {
email: myUser.email,
name: myUser.name,
uid: myUser.uid,
},
groupName,
groupDescription,
groupProfilePic: groupProfileFinalPic(),
projects: '',
})
.then(() => {
console.log('Groups oluşturuldu.');
})
.catch(e => {
Alert.alert('Hata', 'Beklenmedik bir hata meydana geldi.');
console.log(e.message);
});
dispatch({
type: ADD_PROJECT_GROUP,
});
};
You are not awaiting groupProfileFinalPic(). This should be done before creating the action you want to dispatch.
groupProfileFinalPic().then(groupProfilePic => {
return firebase
.database()
.ref("/groups/" + key)
.set({
admin: {
email: myUser.email,
name: myUser.name,
uid: myUser.uid
},
groupName,
groupDescription,
groupProfilePic,
projects: ""
})
.then(() => {
console.log("Groups oluşturuldu.");
})
.catch(e => {
Alert.alert("Hata", "Beklenmedik bir hata meydana geldi.");
console.log(e.message);
});
});
I have no clue what the last dispatch is for, you might want to do that in one of the callbacks. Your code is to verbose for an SO question, but I hope this helps anyways.
You are using both await and then on the same call. To use await, you can arrange it something like
const uploadImage = async (imageSource, whereToUpload) => {
...
try {
let data = await RNFS.fs.readFile(uploadUri, 'base64')
let uploadBlob = await Blob.build(data, { type: `${mime};BASE64` }))
...etc...
return finalResult
catch (e) {
// handle error
}
}

Mock-axios-adapter not mocking get request

I'm trying to test this function:
export const fetchCountry = (query) => {
return dispatch => {
dispatch(fetchCountryPending());
return axios.get(`${process.env.REACT_APP_API_URL}/api/v1/countries/?search=${query}`)
.then(response => {
const country = response.data;
dispatch(fetchCountryFulfilled(country));
})
.catch(err => {
dispatch(fetchCountryRejected());
dispatch({type: "ADD_ERROR", error: err});
})
}
}
Here is my test:
describe('country async actions', () => {
let store;
let mock;
beforeEach(() => {
mock = new MockAdapter(axios)
store = mockStore({ country: [], fetching: false, fetched: false })
});
afterEach(() => {
mock.restore();
store.clearActions();
});
it('dispatches FETCH_COUNTRY_FULFILLED after axios request', () => {
const query = 'Aland'
mock.onGet(`/api/v1/countries/?search=${query}`).reply(200, country)
store.dispatch(countryActions.fetchCountry(query))
.then(() => {
const actions = store.getActions();
expect(actions[0]).toEqual(countryActions.fetchCountryPending())
expect(actions[1]).toEqual(countryActions.fetchCountryFulfilled(country))
});
});
When I run this test, I get an error UnhandledPromiseRejectionWarning and that fetchCountryPending was not received and that fetchCountryRejected was. It seems as if onGet() is not doing anything. When I comment out the line
mock.onGet('/api/v1/countries/?search=${query}').reply(200, country), I end up getting the exact same result, making me believe that nothing is being mocked. What am I doing wrong?
I couldn't get the .then(() => {}) to work, so I turned the function into an async function and awaited the dispatch:
it('dispatches FETCH_COUNTRY_FULFILLED after axios request', async () => {
const query = 'Aland'
mock.onGet(`/api/v1/countries/?search=${query}`).reply(200, country)
await store.dispatch(countryActions.fetchCountry(query))
const actions = store.getActions();
expect(actions[0]).toEqual(countryActions.fetchCountryPending())
expect(actions[1]).toEqual(countryActions.fetchCountryFulfilled(country))
});

Resources