Is it possible to updateQueryData on a new nonexistent query - RTK Query? - reactjs

I've an api created with RTK Query, and I have a create endpoint that pessimistically updates other queries:
create: builder.mutation<
{ id: string },
Req
>({
query: (req) => ({
url: "",
method: "POST",
body: req,
}),
async onQueryStarted(req, { dispatch, queryFulfilled }) {
try {
const {
data: { id },
} = await queryFulfilled;
dispatch(
apiSvc.util.updateQueryData(
"getFoos",
{ specialId: req.specialId },
(draft) => {
draft.unshift({
...req,
id
});
}
)
);
dispatch(
apiSvc.util.updateQueryData(
"getSingleFoo",
{ specialId: req.specialId, otherSpecialId: req.otherSpecialId },
(draft) => {
Object.assign(draft, {
...req,
id
});
}
)
);
} catch (e) {
console.error(e);
}
},
}),
But updating the getSingleFoo doesn't update the cache value correctly, only getFoos is updated.
Is it possible to do this? If so how?

If anyone wonders here, I asked in the repo.

Related

MongoDB / ReactJS Patch handler / findOneAndUpdate not working

in the following code, I'm attempting to update the Checkpoints field for one of my objects within the projects collection. UpdatedCheckpoints is working correctly, so I believe the first block of code works. But the change isn't logging to the database so it doesn't persist. What's going wrong?
const onApprovedSubmit = useCallback(
async (e) => {
e.preventDefault();
let updatedCheckpoints = props.project.Checkpoints;
updatedCheckpoints[props.checkpointIndex].checkpointSubmitted = true;
console.log('here');
try {
let projectId = props.project._id;
await fetcher('/api/projects', {
method: 'PATCH',
headers: { 'Content-type': 'application/json' },
body: JSON.stringify({ Checkpoints: updatedCheckpoints }),
id: projectId,
});
toast.success('Your checkpoint has been updated');
} catch (e) {
toast.error(e.message);
}
},
[props],
);
handler.patch(async (req, res) => {
const db = await getMongoDb();
const project = await updateProjectById(db, req.id, req.body);
res.json({ project });
});
export async function updateProjectById(db, id, data) {
return db
.collection('projects')
.findOneAndUpdate(
{ _id: new ObjectId(id) },
{
$set: data,
},
{ returnDocument: 'after' },
)
.then(({ value }) => value);
}

react-query customHook refetchOnWindowFocus

I am creating individual hooks using react-query. Where would I add in refetchOnWindowFocus: false ? as it is not currently being read and the data is being re-fetched when returning to the window.
const useFetchOverview = () => {
return useQuery(["userData", { refetchOnWindowFocus: false }],
async () => {
const { data } = await axios({
url: useFetchOverviewUrl,
headers: { ...getHeaders(reduxState) },
method: "get"
});
return data;
});
};
const { isLoading, data: userOverviewData } = useFetchOverview();
this should be third parameter after fuinction:
return useQuery(["userData"],
async () => {
const { data } = await axios({
url: useFetchOverviewUrl,
headers: { ...getHeaders(reduxState) },
method: "get"
});
return data;
}, { refetchOnWindowFocus: false });
ex: useQuery(queryKey, queryFn?, options)
check this for your reference: https://tanstack.com/query/v4/docs/reference/useQuery?from=reactQueryV3&original=https://react-query-v3.tanstack.com/reference/useQuery
OR you can write it for global:
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
},
},
})

Res.json not sending data in React app and appearing as undefined

I am developing a React with Nodejs backend and I have implemented "stripe" in order to process payments. The problem appears when I need to get the URL which should redirect me to the Stripe payment form. I should get it from a json response, but it is empty, no matter what I send. I've even tried sending really simple data, but it still doesn't work. I've used it before without problems in this project, so I don't know what I am doing wrong here. Can anyone offer any help? Thank you!
This is the router file, which creats the session for the payment and which is also supposed to send the needed URL. I tested and the URL is correct, it is just a matter of sending it through res.json
router.post("/payment", async(req, res) => {
const course = await Courses.findByPk(req.body.items[0].id);
const storeItems = new Map([
[course.id, { priceInCents: course.price, name: course.title }],
])
try {
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
mode: 'payment',
line_items: req.body.items.map(item => {
const storeItem = storeItems.get(item.id)
return {
price_data: {
currency: "usd",
product_data: {
name: storeItem.name,
},
unit_amount: storeItem.priceInCents,
},
quantity: item.quantity,
}
}),
success_url: 'http://localhost:3000/profile-page',
cancel_url: `http://localhost:3000/course-details/${course.id}`
})
res.json({ url: session.url });
} catch (e) {
res.status(500).json({ error: e.message });
}
});
And this is where I should be getting the URL back, but I don't. Instead, when I console.log it, I get "undefined".
if (response.data.error) {
alert(response.data.error);
} else {
axios.post("http://localhost:3001/users_courses/payment", {
items: [
{ id: data.id, quantity: 1 },
],
}, {
headers: {
accessToken: localStorage.getItem("accessToken"),
},
}).then(res => {
if(res.ok) return res.json();
return res.json().then(json => Promise.reject(json));
}).then (( { url }) => {
window.location.href = url;
console.log(url + " this is the url");
}).catch(e => {
console.error(e.error);
})
}
I think it has to do with how you’re handling your axios post, I think with a small change like I suggested below this should work for you.
axios
.post(
"http://localhost:3001/users_courses/payment",
{
items: [{ id: response.data.id, quantity: 1 }],
},
{
headers: {
accessToken: localStorage.getItem("accessToken"),
},
}
)
.then(({ data: { url } }) => {
window.location.replace(url);
console.log(url + " this is the url");
})
.catch((e) => {
console.error(e.error);
});
Note that axios is not like the fetch API where you have to handle the transformation of the response body into the json object.

How to make api call with optional payload in React JS

I am trying to call API in React JS with AXIOS. I need to send payload as optional when productID has value.
This is my service.js file
fetchProducts: (payload) => put(`/products`, payload),
fetchProductsProductID: (params, payload) => put(`/products`, payload, { params }),
products.js
useEffect(() => {
if (productID) {
CommonSrv.fetchProductsProductID(
{ productID: productID },
{
data: data,
},
)
.then((resp) => {
console.log(resp)
})
.catch((err) => {
console.log(err)
});
} else {
CommonSrv.fetchProducts({ data: data })
.then((resp) => {
console.log(resp)
})
.catch((err) => {
console.log(err)
});
}
}, [])
within the then and catch blocks same conditions I need to use. Because of productID, I am duplicating my code a lot how can I simply this code.
You can try something like that!
(productID ?
CommonSrv.fetchProductsProductID(
{ productID: productID },
{
data: data,
},
)
:
CommonSrv.fetchProducts({ data: data }))
).then(.....).catch(...)

React Context - Post Like / Unlike feature

I am building post like / unlike feature using React context, but I have no idea what to do in reducer to update UI. Currently when I click like / unlike button, ui doesn't update instantly, have to refresh page to see the update.
backend logic
exports.likePost = async (req, res) => {
try {
const result = await Post.findByIdAndUpdate(
req.body.postId,
{
$push: { likes: req.body.userId },
},
{ new: true }
);
return res.json(result);
} catch (err) {
console.log(err.message);
}
};
exports.unlikePost = async (req, res) => {
try {
const result = await Post.findByIdAndUpdate(
req.body.postId,
{
$pull: { likes: req.body.userId },
},
{ new: true }
);
return res.json(result);
} catch (err) {
console.log(err.message);
}
};
component
{post.likes.includes(loggedInUser._id) ? (
<IconButton
color="secondary"
component="span"
onClick={() => unlikePost(loggedInUser._id, post._id)}
>
<Like />
</IconButton>
) : (
<IconButton
color="secondary"
component="span"
onClick={() => likePost(loggedInUser._id, post._id)}
>
<Unlike />
</IconButton>
)}
context
const initialState = {
posts: [],
};
// Like post
const likePost = async (userId, postId) => {
try {
const res = await axios.put(
`/api/posts/like`,
{ userId, postId },
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
}
);
dispatch({ type: "LIKE_POST", payload: res.data });
} catch (err) {
console.log(err);
}
};
// Unlike post
const unlikePost = async (userId, postId) => {
try {
const res = await axios.put(
`/api/posts/unlike`,
{ userId, postId },
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
}
);
dispatch({ type: "UNLIKE_POST", payload: res.data });
} catch (err) {
console.log(err);
}
};
reducer
case "LIKE_POST":
return {
...state,
posts: // ???
),
};
case "UNLIKE_POST":
return {
...state,
posts: // ???,
};
What should be the logic for reducer?
Something like this:
case "LIKE_POST":
return {
...state,
like: action.likeValue,
};
case "UNLIKE_POST":
return {
...state,
unlike: action.unlikeValue,
};
When you want to change the value:
dispatch({ type: "LIKE_POST", likeValue: res.data });
dispatch({ type: "UNLIKE_POST", unlikeValue: res.data });
In your initial state:
const initialState = {
posts: [],
like: [],
unlike: [],
};
Here is a good explanation, which helped me: link

Resources