HTTP put and get(id) request ReactQuery - reactjs

I change the redux in my project to ReactQuery,and i got some problem with put req in my code.
this is my code
const { dispatch } = store;
const editClientDataAsync = async ( id,data ) => {
await axiosObj().put(`clients/${id}`,data);
}
const { mutateAsync: editClientData, isLoading } = useMutation(['editClientData'], editClientDataAsync, {
onSuccess: () => dispatch({ type: SUCCESS_DATA, payload: { message: "Success" } }),
onError: () => dispatch({ type: ERROR_DATA, payload: { message: "Error" } })
});
return { editClientData, isLoading }
}
same problem with when i try to get some req with id
const id = useSelector((state) => state?.clientData?.clientInfo?.data.id)
const getClientDetails = async ({ queryKey }) => {
const [_, { id }] = queryKey;
console.log(queryKey)
if (!id)
return;
const { data } = await axiosObj().get(`clients/${id}`)
console.log(data)
return data;
}
const { data: clientDetails, isLoading } = useQuery(['ClientId', { id }], getClientDetails)
return { clientDetails, isLoading }

Mutation functions only take 1 argument
Check where you use the editClientData mutation and pass the arguments in one object.
const editClientDataAsync = async ({ id, data }) => {
await axiosObj().put(`clients/${id}`,data);
}
return useMutation(['editClientData'], editClientDataAsync, ...);
Are you sure you get an id passed to the function?
You can disable the query until you get that id with the enabled option, so you don't make an unnecessary http call.
const id = useSelector((state) => state?.clientData?.clientInfo?.data.id)
const getClientDetails = async (id) => {
const { data } = await axiosObj().get(`clients/${id}`)
return data;
}
return useQuery(['client', id], () => getClientDetails(id), { enabled: !!id })
Disable/pausing queries

Related

React-query useInfiniteQuery: getNextPageParam not working

I'm stuck using useInfiniteQuery.
The first call works fine, but the next page is not called with getNextPageParam
const getProductItems = async (par) => {
console.log("axios :", par);
const res = await axios.get(`/api/v1/products`, {
params: par,
});
return {
result: res.data,
};
};
export default function useGetProductItems(params) {
const { data, isLoading, fetchNextPage, hasNextPage, isFetching } =
useInfiniteQuery(
["getItems"],
({ pars = params }) => getProductItems(pars),
{
getNextPageParam: (res) => {
console.log(res);
const nextParams = {
...res.result.pageInfo,
page: res.result.pageInfo.page + 1,
};
console.log("next :", nextParams);
return nextParams;
},
select: (data) => {
return data.pages[0].result.data;
},
}
);
return {
data,
isLoading,
fetchNextPage,
hasNextPage,
isFetching,
};
}
And the Query Client setting is like this
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
},
},
queryCache: new QueryCache({
onError: errorHandler,
}),
mutationCache: new MutationCache({
onError: errorHandler,
}),
});
As I am new to react-query, I am also wondering if there is any data that must be received from the API.
plz answer for me
You can access pageParam and send it as argument to your fetching function. Also it'd be a good idea to check if there really is a next page before incrementing the actual page number in getNextPageParam. Something like this:
const { data, isLoading, fetchNextPage, hasNextPage, isFetching } =
useInfiniteQuery(
['getItems'],
({ pageParam = 1 }) => getProductItems(pageParam), // pageParam defaults to the first page
{
getNextPageParam: lastPage => {
return lastPage.result.pageInfo.page < lastPage.result.pageInfo.totalPages // Here I'm assuming you have access to the total number of pages
? lastPage.result.pageInfo.page + 1
: undefined // If there is not a next page, getNextPageParam will return undefined and the hasNextPage boolean will be set to 'false'
},
select: data => {
return data.pages[0].result.data
},
}
)
I don't have information about how is your API endpoint built, but typically the request should look, for example, like this:
const getProductItems = async (page) => {
const res = await axios.get(`/api/v1/products?page=${page}`);
return {
result: res.data,
};
};

Reactjs - Firebase : Cancel Old Requests

I'm new to Firebase Realtime Database, and i'm trying to implement a search field that allow users to search for other users and view their profiles.
The Problem Is:
I want to make the search realTime(on each input change).but whenever a new request's sent, the old request is still working in the backend which's causing unexpected behavior,i've wrapped this functionality in a useEffect Hook,old sideEffects has to be cleaned up to make the query results predictable,how can i abort the previous request.
useSearchOwner Custom Hook:
const useSearchOwner = () => {
const [{ SearchValue, SearchResult, Search }, dispatch] = useReducer(
reducer,
{
SearchValue: "",
SearchResult: "",
Search: false,
}
);
const isFirstRender = useRef(true);
const onChangeHandler = (e) =>
dispatch({
type: ACTIONS.UPDATE_SEARCH_VALUE,
payload: { searchValue: e.target.value },
});
useEffect(() => {
if (isFirstRender.current) {
isFirstRender.current = false;
return;
}
dispatch({ type: ACTIONS.START_SEARCHING });
const DispatchQueryByResult = async () => {
const ArrayOfOwners = await FirebaseUtilityInstance.SearchOwnerResult(
SearchValue
);
dispatch({
type: ACTIONS.UPDATE_SEARCH_RESULT,
payload: { searchResult: ArrayOfOwners },
});
dispatch({ type: ACTIONS.STOP_SEARCHING });
return () => {
FirebaseUtilityInstance.SearchOwnerCleanup();
};
};
DispatchQueryByResult();
}, [SearchValue]);
useEffect(() => {
console.log(SearchResult);
}, [SearchResult]);
return {
onChangeHandler: onChangeHandler,
Query: SearchValue,
QueryResult: SearchResult,
isSearching: Search,
};
};
Firebase Method To Do Query:
SearchOwnerResult = async (Query) => {
const { firstName, lastName } = getFirstNameAndLastName(Query);
let ArrayOfOwners = [];
await this.Database()
.ref("users")
.orderByChild("UserType")
.equalTo("owner")
.once("value", (snapshot) => {
const OwnersContainer = snapshot.val();
const keys = Object.keys(OwnersContainer);
for (let i = 0; i < keys.length; i++) {
const CurrentOwner = OwnersContainer[keys[i]];
if (
CurrentOwner.FirstName === firstName ||
CurrentOwner.LastName === lastName
) {
ArrayOfOwners.push(OwnersContainer[keys[i]]);
}
}
});
return ArrayOfOwners;
};

Dispatch multiples http request React/Redux

I'm trying to dispatch more than one axios request inside my method. However, it is not working.
export const getImages = (res) => {
return {
type: actionTypes.GET_IMAGES,
payload: res
}
}
export const loadImages = (imgs, cId) => {
return dispatch => {
let data = [];
for(const i of imgs) {
const id = i.id;
axios.get(`${api.URL}/test/${cId}/files/${id}`)
.then(res => {
if(res.data !== -1) {
const obj = {
name: res.data,
desc: i.caption
};
data(obj);
}
//dispatch(getImages(data));
});
}
console.log('Action:');
console.log(data);
dispatch(getImages(data));
}
}
The console log does not print anything. Do I need to dispatch inside the .then()? If so, how can I run multiples requests before dispatching?
Thanks

I'm getting following error in Jest ReferenceError: Response is not defined

First I had a typescript issue that my mocked data doesn't match to Response type. Then I tried to create mock data with Response constructor and got that error.
I have the following code
const HttpRequest = async function (
url: string,
options: RequestInit,
): Promise<Response> {
try {
return await fetch(url, options);
} catch (error) {
return null;
}
};
export default HttpRequest;
And following test:
const res = new Response();
window.fetch = jest.fn(
() => new Promise((resolve) => {
return resolve(res);
})
);
describe('HttpService', () => {
it('fetchWithFeedback', async () => {
const data = await HttpRequest('/api', { method: 'GET' });
expect(data).toEqual(res);
});
});
Change
const changeField = (field, id, value) => {
const newPropertyData = { ...propertyData };
if (newPropertyData.id === id) {
newPropertyData.field = value;
}
};
to
const changeField = (field, id, value) => {
if (propertyData.id === id) {
setPropertyData({ ...propertyData, [field]: value })
}
};
You're not updating your state in your onChange, so it's never able to update the value, which is still "".

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
}
}

Resources