how to call reactQuery refetch in input onchange event in reactjs - reactjs

In my React application, I need to call does exit API. API call should happen when change event in the input for that, I am using the reactQuery refetch to do that.
I had tried with below code
const [createObj, setCreateObj] = useState(mCreateObj);
const { data: doexit, refetch: doexitRefetch } = useQuery('getDoexit', () => api.doexitAPI(createObj.c_name), { enabled: false });
const handleInput = ({ target: { name, value } }) => { setCreateObj(state => ({ ...state, [name]: value }), []); }
export const doexitAPI= (value) => axios.get(/doexist/${value}, { headers: setHeader }).then(res => res);
useEffect(() => { console.log(createObj) doexitRefetch(); }, [createObj.mx_name])
How to call in input onchange event

You can invalidate your query and handle fetch data again with query keys.
https://react-query.tanstack.com/guides/query-keys#if-your-query-function-depends-on-a-variable-include-it-in-your-query-key
const { data: doexit, refetch: doexitRefetch } = useQuery(['getDoexit', createObj.mx_name], () => api.doexitAPI(createObj.c_name), { enabled: false });

Related

Pausing react query and re-fetching new data

I have a useQuery which is disabled in a react function component. I have another useQuery that uses mutate and on the success it calls refetchMovies(). This all seems to work well but I'm seeing old data in the refetchMovies. Is there a way for to get the refetchMovies to always call fresh data from the server when its called ?
const MyComponent = () => {
const {data, refetch: refetchMovies} = useQuery('movies', fetchMovies, {
query: {
enabled: false
}
})
const {mutate} = useQuery('list', fetchList)
const addList = useCallback(
(data) => {
mutate(
{
data: {
collection: data,
},
},
{
onSuccess: () => refetchMovies(),
onError: (error) => console.log('error')
}
)
},
[mutate, refetchMovies]
)
return (
<div onClick={addList}> {data} </div>
)
}
Try to invalidate the query in your onSuccess callback instead of manually refetching it:
https://tanstack.com/query/v4/docs/react/guides/query-invalidation
Example:
// Invalidate every query with a key that starts with `todos`
queryClient.invalidateQueries({ queryKey: ['todos'] })

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

Recoil Async data request with atomFamily

I'm using an atomFamily with a default value of a selectorFamily to get some order data:
export const orderState = atomFamily<Order | undefined, string>({
key: 'orderFamily',
default: selectorFamily({
key: 'orderSelectorFamily',
get:
orderId =>
async ({ get }) => {
try {
const response = await getOrder(orderId);
return response.data;
} catch (e) {
console.log('error', e);
}
},
}),
});
This is used when the page loads and id is captured from the URL and used in a React component:
export const useGetOrderValue = (orderId: string) => {
return useRecoilValue_TRANSITION_SUPPORT_UNSTABLE(orderState(orderId));
};
And in the Component
const order = useGetOrderValue(id);
I also need to be able to get the order data from an order search that'll then redirect to the order page. So I'm getting the order data from a request and setting it manually using a useRecoilCallback function:
const getOrder = useRecoilCallback(
({ set }) =>
async (orderId: string) => {
try {
const response = await requestGetOrder({ orderId });
set(orderState(orderId), response.data);
} catch (e) {
console.log('error', e);
}
},
[],
);
It all seems to work fine but I feel like I'm duplicating effort within the useRecoilCallback. Is there a better way to do this?

Redux async call with then does not wait for api response

I'm defining a Redux service to call an api endpoint:
export const TrackersApi = {
getBasicsTrackers: async (): Promise<ReturnType<typeof recreator>> => {
const url = "/api/getbasictrackers"
const {data, statusText} = await axios.get(url, { withCredentials: true });
if(statusText !== 'OK' && statusText !== 'No Content') throw new Error('Wrong response from getbasictrackers')
const result = recreator(data)
console.log({result})
return result
},
The log returns the json response.
Then I inject this in a component on mount:
componentDidMount = () => {
store.dispatch(getBasicTrackers()).then(() => {
if(this.props.trackers) {
this.setState({
sortedAndFilteredTrackers : this.props.trackers
})
}
if(this.props.folders) {
this.setState({
sortedAndFilteredFolders: this.props.folders
})
}
console.log('trackers', this.props.trackers)
})
}
However the log here returns an empty array. I tried first without the then and I had the same issue.
How can I make it so that the setState is called only once the API response is received?
Additional info: This props is then used to fill in a table. However the table remains empty, which is the key issue here
It is mapped through this:
const mapStateToProps = (state: ReduxStore.State) => ({
trackers: state.trackersData.rawTrackers ? Object.values(state.trackersData.rawTrackers).map(item => ({...item, checked: false})) : [],
folders: state.trackersData?.folders ? Object.values(state.trackersData.folders).map((folder: any) => ({...folder.summary, checked: false})) : []
})

react select load async options does not load

I want to load options from backend. So i have to fetch data from API and then update options.
But i don't know how to do it. Can someone help? Here's my code:
function myComponent() {
const loadOptions = () => {
console.log('on load options function')
axios.get(`/api/admin/roles`)
.then((response) => {
const options = []
response.data.permissions.forEach((permission) => {
options.push({
label: permission.name,
value: permission.id
})
})
return options
})
}
return (
<AsyncSelect
isMulti
cacheOptions
loadOptions={loadOptions}
/>
)
}
By the way nothing gets logged at all and that means the loadOptions function does not run. Here's my response from API:
response: {
data: {
permissions: [{
id: 13,
name: 'deposit'
}, {
id: 14,
name: 'withdraw'
}]
}
}
The issue you're experiencing seems to be due to the fact that you're not returning anything at the top-level of the loadOptions function.
The documentation highlights two ways to define your loadOptions function.
Using callbacks:
const loadOptions = (inputValue, callback) => {
setTimeout(() => {
callback(options);
}, 1000);
};
Using promises:
const loadOptions = inputValue =>
new Promise(resolve => {
setTimeout(() => {
resolve(options);
}, 1000);
});
In your case, it might be simplest to try the callback option first since your existing syntax is conducive with it.
const loadOptions = (inputValue, callback) => {
console.log('on load options function')
axios.get(`/api/admin/roles`)
.then((response) => {
const options = []
response.data.permissions.forEach((permission) => {
options.push({
label: permission.name,
value: permission.id
})
})
callback(options);
})
}
In the future you can optionally leverage the inputValues parameter to down-filter results.
Your loadOptions function must return a promise. Also you can pass defaultOptions as true to make the request fire for initial set of options
const loadOptions = () => {
console.log('on load options function')
return axios.get(`/api/admin/roles`)
.then((response) => {
const options = []
response.data.permissions.forEach((permission) => {
options.push({
label: permission.name,
value: permission.id
})
})
return options
})
}
function myComponent() {
return (
<AsyncSelect
isMulti
cacheOptions
defaultOptions
loadOptions={loadOptions}
/>
)
}
P.S For performance reasons, you can declare your loadOptions function outside of the component so that it doesn't get recreated on every re-render
AsyncSelect expects a defaultOptions prop, which you have not provided. The docs are unclear about what behavior it should exhibit in this case, but I'd guess it defaults to loading on filter.
Try this
const loadOptions = async () => {
const response = await axios.get(`/api/admin/roles`)
const result = await response.data
return await result.permissions.map((permission) => ({
label: permission.name,
value: permission.id
}))
}

Resources