React useEffect hook running infinite loop despite static dependencies - google-cloud-firestore

Can someone please point to me what part of this code is causing an infinite loop?
I have tried wrapping this in useCallback as well but it still runs forever.
slug is the page url that will not change over time
likesCollectionRef is also goint to remain constant
isAuth can change overtime depending on if the user is logged in or out
export default function CommentForm({ slug, isAuth, setReloadTS }) {
const [isLiked, setIsLiked] = useState(false);
const likesCollectionRef = collection(fireStore, 'likes');
useEffect(() => {
if (!isAuth) return;
const qry = query(
likesCollectionRef,
where('slug', '==', slug),
where('author.id', '==', auth.currentUser.uid)
);
const findLike = async () => {
const data = await getDocs(qry);
console.log(`initial like: ${data.docs}`);
setIsLiked(data.docs !== 'undefined' && data.docs);
};
findLike();
}, [slug, isAuth, likesCollectionRef]);
}

likesCollectionRef is declared each render cycle. Place the likes collection reference in a React ref so it's a stable reference. auth also appears to be an external dependency. If it's external to the component this is ok, but if it's internal to the component it should be added to the dependency array.
export default function CommentForm({ slug, isAuth, setReloadTS }) {
const [isLiked, setIsLiked] = useState(false);
const likesCollectionRef = useref(collection(fireStore, 'likes'));
useEffect(() => {
if (!isAuth) return;
const qry = query(
likesCollectionRef.current,
where('slug', '==', slug),
where('author.id', '==', auth.currentUser.uid)
);
const findLike = async () => {
const data = await getDocs(qry);
console.log(`initial like: ${data.docs}`);
setIsLiked(data.docs !== 'undefined' && data.docs);
};
findLike();
}, [isAuth, likesCollectionRef, slug]);
...
}

Related

use Effect not working to bring up my product, using axios use params,

This code is not working for me i am trying to pull data from my mongodb
const ProductScreen = ({ match }) => {
const [product, setProduct] = useState({});
const { id } = useParams();
useEffect(() => {
const fetchProduct = async () => {
const { data } = await axios.get(
`/api/product/${encodeURIComponent(id)}`
);
setProduct(data);
};
fetchProduct();
}, []);
};
pull data from server of mongo db
It is possible when the component first mounts, id is null and useParams() doesn't get it till the second render. So add an if statement in your useEffect to make sure the id is present. Also add id to the dependency array, so if the id changes, you will refetch the data for it. Otherwise, with an empty dependency array, the useEffect will only run on first mount.
const ProductScreen = ({ match }) => {
const [product, setProduct] = useState({});
const { id } = useParams();
useEffect(() => {
const fetchProduct = async () => {
const { data } = await axios.get(
`/api/product/${encodeURIComponent(id)}`
);
setProduct(data);
};
if (id) {
fetchProduct();
}
}, [id]);
};

React-query: invalidateQueries doesn't work

I'm trying to invalidate queries when I create new comment.
const { data: comments } = useQuery("getComments", () => getComments({ originalKind: "NOTICE", originalSeq: id }));
const createCommentMutation = useMutation(postComment, {
onSuccess: async () => {
const queryClient = new QueryClient();
await queryClient.invalidateQueries("getComments");
},
});
The comment is created successfully, but invalidateQueries dose not working.
There is no default options...
every time i create comment, the query will invalidated
If you create a new QueryClient, it will have a new QueryCache, which is not associated with the cached data of your query. That's not how it works, and that's also not what any of the official examples / docs are showing.
What you have to do is get access to the client with useQueryClient() - another hook exported from react-query. This will give you the singleton QueryClient that you have put into the QueryClientProvider:
import { useQueryClient } from '#tanstack/react-query'
const queryClient = useQueryClient()
const createCommentMutation = useMutation(postComment, {
onSuccess: async () => {
await queryClient.invalidateQueries("getComments");
},
});

Propagate live updates return promise object instead of value

Working on beginner steps toward vue 3 and firestore migration. Stuck on simple.
import { getUsersCount } from "/src/firebase";
setup() {
const usersCount = getUsersCount();
return {
usersCount,
};
},
Why it returns Promise Object, I cant find in manuals.
export const getUsersCount = async () => {
// const querySnap = await getDocs(query(collection(db, "users")));
const q = query(collection(db, "users"));
const unsub = onSnapshot(q, (querySnapshot) => {
console.log("usersCount33: ", querySnapshot.size);
//unsub();
return querySnapshot.size;
});
}
Nad the last part with template,
<template>
<p>Users Count: {{ usersCount }}</p>
</template>
If you return the value inside a callback, you can not use async await syntax. You should do this:
export const getUsersCount = () => {
return new Promise((resolve, reject) => {
const q = query(collection(db, "users"));
const unsub = onSnapshot(q, (querySnapshot) => {
return resolve(querySnapshot.size)
});
})
}
// You still need to wait getUsersCount when using it
const usersCount = await getUsersCount();

Connect Apollo with mongodb

I want to connect my Apollo server with my mongoDB. I know there are many examples out there, but I get stuck at the async part and did not found a solution or example for that (that's strange, am I completly wrong?)
I started with the example from next.js https://github.com/zeit/next.js/tree/master/examples/api-routes-apollo-server-and-client .
But the mongodb integration is missing.
My code
pages/api/graphql.js
import {ApolloServer} from 'apollo-server-micro';
import {schema} from '../../apollo/schema';
const apolloServer = new ApolloServer({schema});
export const config = {
api: {
bodyParser: false
}
};
export default apolloServer.createHandler({path: '/api/graphql'});
apollo/schema.js
import {makeExecutableSchema} from 'graphql-tools';
import {typeDefs} from './type-defs';
import {resolvers} from './resolvers';
export const schema = makeExecutableSchema({
typeDefs,
resolvers
});
apollo/resolvers.js
const Items = require('./connector').Items;
export const resolvers = {
Query: {
item: async (_parent, args) => {
const {id} = args;
const item = await Items.findOne(objectId(id));
return item;
},
...
}
}
apollo/connector.js
require('dotenv').config();
const MongoClient = require('mongodb').MongoClient;
const password = process.env.MONGO_PASSWORD;
const username = process.env.MONGO_USER;
const uri = `mongodb+srv://${username}:${password}#example.com`;
const client = await MongoClient.connect(uri);
const db = await client.db('databaseName')
const Items = db.collection('items')
module.exports = {Items}
So the problem is the await in connector.js. I have no idea how to call this in an async function or how to provide the MongoClient on an other way to the resolver. If I just remove the await, it returns – obviously – an pending promise and can't call the function .db('databaseName') on it.
Unfortunately, we're still a ways off from having top-level await.
You can delay running the rest of your code until the Promise resolves by putting it inside the then callback of the Promise.
async function getDb () {
const client = await MongoClient.connect(uri)
return client.db('databaseName')
}
getDb()
.then(db => {
const apollo = new ApolloServer({
schema,
context: { db },
})
apollo.listen()
})
.catch(e => {
// handle any errors
})
Alternatively, you can create your connection the first time you need it and just cache it:
let db
const apollo = new ApolloServer({
schema,
context: async () => {
if (!db) {
try {
const client = await MongoClient.connect(uri)
db = await client.db('databaseName')
catch (e) {
// handle any errors
}
}
return { db }
},
})
apollo.listen()

Error when combining Express Router with Massive.js db call

When making an async/await call to database from an express router to postgres db via massive.js instance, the correct response from db is received, but the router apparently returns before async function finishes; therefore, the test invocation returns undefined. From the console out (below), it seems clear that the async function is not waited for >_<
Is wrapping the router in order to pass the app instance causing the issue?
app.js
const app = express();
const massiveInstance = require("./db_connect");
const routes = require("./routes");
const PORT = 3001;
const server = massiveInstance.then(db => {
// Add db into our app object
app.set("db", db);
app.use("/api", routes(app));
app.listen(PORT, () => {
console.log("Server listening on " + PORT);
});
});
routes.js
const router = require("express").Router();
const { countRegions } = require("./db_queries");
const routes = app => {
const db = app.get("db");
router.get("/regions/count", async (request, response) => {
try {
const total = await countRegions(db);
console.log(`There are ${total} regions.`);
response.send(`There are ${total} regions.`);
} catch (err) {
console.error(err);
}
});
return router;
};
module.exports = routes;
db_queries.js
const countRegions = db => {
db.regions.count().then(total => {
console.log(`db has ${total} count for regions`);
return total;
});
};
module.exports = {
countRegions,
};
console output
Server listening on 3001
There are undefined regions.
db has 15 count for regions
You are not returning a promise returned by then in countRegions method.
So you should add return in your code like this
const countRegions = db => {
//here
return db.regions.count().then(total => {
console.log(`db has ${total} count for regions`);
return total;
});
};
or simply do,
return db.regions.count();