I just started with Next js. The question I have is that in express projects we have a connection to the database once and we put it in the main file of the program, i.e. app.js. but in Next js as I understand so far, the connection to the database must be inside the api file. Doesn't this cause the connection to be reconnected every time the api is called? Is it necessary to have a file like app.js in order to connect to mongo inside it?
thanks
create one separate file and add following code in that file.
import mongoose from 'mongoose';
const connection = {}
const dbConnect = async () => {
if (connection.isConnected) return
const db = await mongoose.
connect(process.env.DB_URL, { useNewUrlParser: true, useUnifiedTopology: true })
connection.isConnected = db.connections[0].readyState
}
export default dbConnect
now only you need to call dbConnect() function every where you are performing the db operation.
Related
I'm trying to read some on-chain data with ethers.js JsonRpcProvider. I'm calling it with an Alchemy key, stored in a .env file.
edit : Making this variable only visible to server side is intentionnal, because I do not want to share this "sensible" information. Maybe it's not the right way to do this, I don't know...
I can't load my data on the client side, but on the server side, everything seems fine :/
What I'm doing wrong?
// ALCHEMY_API_KEY_URL is in .env file
const passiveProvider = new ethers.providers.JsonRpcProvider(process.env.ALCHEMY_API_KEY_URL)
// everything's fine on server side
console.log(passiveProvider)
const whiteListContract = new ethers.Contract(WHITELIST_CONTRACT_ADDRESS, abi, passiveProvider)
export default function Home() {
const [value, setValue] = React.useState("")
React.useEffect(() => {
async function getNumAddressesWhitelisted(contract) {
try {
// we're in useEffect, client-side, nothing works here :/
// dunno if this executes
const clientTx = await contract.numAddressesWhitelisted()
console.log("numAddressesWhitelisted : ", clientTx)
setValue(clientTx)
} catch (err) {
// we drop here each time
console.log("there is an error ! ",err)
// error message dropped :
// there is an error ! Error: could not detect network (event="noNetwork", code=NETWORK_ERROR, version=providers/5.7.0)
// at Logger.makeError (index.js?dd68:224:1)
// at Logger.throwError (index.js?dd68:233:1)
// at JsonRpcProvider.eval (json-rpc-provider.js?8679:442:1)
// at Generator.throw (<anonymous>)
// at rejected (json-rpc-provider.js?8679:6:42)
}
}
getNumAddressesWhitelisted(whiteListContract)
}, [])
return (
<div>
{value}
</div>
)
}
I think this line with the env variable is the issue:
const passiveProvider = new ethers.providers.JsonRpcProvider(process.env.ALCHEMY_API_KEY_URL)
Because environment variables that are inside .env file loaded on the server but not on the client. so passiveProvider is successfully defined on server side but client-side. In order to that env variable work on the client side, you have to add NEXT_PUBLIC_ prefix to the naming
NEXT_PUBLIC_ALCHEMY_API_KEY_URL=...........
now this env variable will be defined on the client side
const passiveProvider = new ethers.providers.JsonRpcProvider(process.env.NEXT_PUBLIC_ALCHEMY_API_KEY_URL)
What's the difference between exposing environment variables in nextjs through the next.config.js vs with the NEXT_PUBLIC prefix?
Ok, I think I've figured out a righter/cleaner way to do this by far :
I needed getServerSideProps. getServerSideProps can only exist in a next.js page, executes code on server side only, and returns props passed to the page.
The logs appears only on server side too, as expected :
export async function getServerSideProps() {
// ALCHEMY_API_KEY_URL is defined in .env file, it's visible only from server side
const passiveProvider = new ethers.providers.JsonRpcProvider(process.env.ALCHEMY_API_KEY_URL)
console.log("passive provider : ", passiveProvider)
const whiteListContract = new ethers.Contract(WHITELIST_CONTRACT_ADDRESS, abi, passiveProvider)
const clientTx = await whiteListContract.numAddressesWhitelisted()
console.log("numAddressesWhitelisted : ", clientTx)
return { props: { clientTx } }
}
export default function Home({ clientTx }) {
return (
<div>
{clientTx}
</div>
)
}
i am using next js and i added getServerSideProps to my project and when i redeployed my project to vercel i am getting the flowing error but my localhost is woeking perfectly
i am using next js and i added getServerSideProps to my project and when i redeployed my project to vercel i am getting the flowing error but my localhost is woeking perfectly
export async function getServerSideProps() {
// Fetch data from external API
const res = await fetch(`https://ask-over.herokuapp.com/questapi`);
const data = await res.json();
// console.log(data);
// Pass data to the page via props
return { props: { data } };
}
module.exports = {
reactStrictMode: true,
}
This is the result of an async call not completing before the next line of code that uses that variable runs. This can happen randomly because that is the nature of async code. The fix is to replace the line where you have data.map(...) with data ? data.map(...) : []; which will return an epty array until data gets its value, then the map function will run and your app should be ok.
In javascript, pretty much any time you're using a variable that is the result of an awaited activity, you should have null checks in place. The code above checks if data has value, then if it does have value, it will run return data.map, otherwise it will return [].
We have a React/GraphQL app inside of a main "app". When the user logs out we want to clear the GQL cache. However, the logout functionality exists in the wrapper app, not the React app.
When we log back in the cache is not cleared, which needs to be solved. A couple of questions on how to solve this:
1) can we check for a cache when the React app tries to create a new instance? Is there a "version" flag we can add?
const client = new ApolloClient({
link: authLink.concat(restLink),
cache: () => {
if (client.cache) {
client.cache.reset()
}
return new InMemoryCache();
}
});
2) or can we find the existing client App through any other window or global object?
3) should the react app set the client as part of local state and then compare client with useRef perhaps? If they don't match, then reset?
Open to suggestions...
The official way to clear the cache is calling resetStore in the client instance. You can get the client instance inside of any component within the Apollo context by using e.g. the useApolloClient hook
function MyLogoutButton() {
const client = useApolloClient();
const onLogout = () => {
backend.logout();
client.resetStore();
};
return <button onClick={onLogout}>Logout</button>;
}
Maybe this is doing what you want to do. You seem to be trying to create a new instance of the client, but this is not needed. The resetStore method was build for exactly this use case.
I have a react app, which must perform a weekly task every Monday #7:58 am. The task is setup as a separate function "notification()". And I want to use the 'CRON' package from NPM to call notification() at the appropriate time.
I have CRON wrapped inside of a function like this:
let mondayNotif = () => {
new CronJob('* 58 7 * * 2', function() {
notification()
}, null, true, 'America/Los_Angeles');
};
My question: where should I call the function mondayNotif(), to make sure that the CronJob is initiated correctly? I thought at first it must be on the backend, but the NPM package doesn't seem to support server-side. But if I call mondayNotif() on the client side, will the CronJob still happen if the site is inactive?
From what I know React JS is front end - it runs on client side. You need a server. In this case a node.js based server. Theroetically if nobody opens the website nothing will be fired up in react js. Look up how to schedule cron jobs on node.js
enter link description here
I found my own answer. But first, a few insights on CronJobs that would have helped me:
CronJobs are essentially a third-party function with an embedded clock. Once they are "initiated", you don't have to call them. The third-party calls them remotely, based on the time that you scheduled in the parameters (ie: "30 6 * * 5").
There is some discrepancy in different blogs about the CRON time. For instance some blogs insisted there are 6 time variables, but I found it worked with 5.
CronJobs should be in a separate file from the body of your main code, typically at the top of your folder structure near your "package.json" & "server.js" files.
It seems to be cleanest to setup all of your CronJob utilities directly inside the cronjob.js file. For instance: I used a separate database connection directly in cronjob.js and by-passed the api routes completely.
CronJobs should be initiated exactly once, at the beginning of the app launch. There are a few ways to do this: package.json or server.js are the most obvious choices.
Here is the file structure I ended up using:
-App
--package.json
--server.js
--cronjob.js
--/routes
--/src
--/models
--/public
...And then I imported the cronjob.js into "server.js". This way the cronjob function is initiated one time, when the server.js file is loaded during "dev" or "build".
For reference, here's the raw cronjob.js file (this is for an email notification):
const CronJob = require('cron').CronJob;
const Department = require('./models/department.js');
const template_remind = require('./config/remindEmailTemplate.js');
const SparkPost = require('sparkpost');
const client = new SparkPost('#############################');
const mongoose = require("mongoose");
const MONGODB_URI =
process.env.MONGODB_URI || "mongodb://localhost:27017/app";
mongoose.Promise = Promise;
// -------------------------- MongoDB -----------------------------
// Connect to the Mongo DB
mongoose.connect(MONGODB_URI, { useNewUrlParser: true }, (err, db) => {
if (err) {
console.log("Unable to connect to the mongoDB server. Error:", err);
} else {
console.log("Connection established to", MONGODB_URI);
}
});
const db = mongoose.connection;
// Show any mongoose errors
db.on("error", error => {
console.log("Mongoose Error: ", error);
});
// Once logged in to the db through mongoose, log a success message
db.once("open", () => {
console.log("Mongoose CRON connection successful.");
});
// ------------------------ Business Logic --------------------------
function weekday(notifications) {
Department.find({"active": true, "reminders": notifications, "week": {$lt: 13}}).distinct('participants', function(err, doc) {
if(err){
// console.log("The error: "+err)
} else {
console.log("received from database... "+JSON.stringify(doc))
for(let i=0; i<doc.length; i++){
client.transmissions.send({
recipients: [{address: doc[i]}],
content: {
from: 'name#sparkmail.email.com',
subject: 'Your email notification',
html: template_remind()
},
options: {sandbox: false}
}).then(data => {})
}
}
})
}
function weeklyNotif() {
new CronJob('45 7 * * 1', function() {weekday(1)}, null, true, 'America/New_York');
new CronJob('25 15 * * 3', function() {weekday(2)}, null, true, 'America/New_York');
new CronJob('15 11 * * 5', function() {weekday(3)}, null, true, 'America/New_York');
}
module.exports = weeklyNotif()
As you can see, I setup a unique DB connection and email server connection (separate from my API file), and ran all of the logic inside this one file, and then exported the initiation function.
Here's what appears in server.js:
const cronjob = require("./cronjob.js");
All you have to do here is require the file, and because it is exported as a function, this automatically initiates the cronjob.
Thanks for reading. If you have feedback, please share.
Noway, do call CronJob from client-side, because if there are 100 users, CronJob will be triggered 100 times. You need to have it on Server-Side for sure
My goal is to update values that stored in MongoDB, therefore I have decided to use mongoose to see data and edit them, However; it gives me an error.
Maybe I am in the wrong way, does anybody has already implemented this kind work.
import * as React from "react";
import * as mongoose from 'mongoose'
export interface State {
}
export default class mongodb extends React.Component<State> {
constructor(props: {}) {
super(props);
}
private setupDb() : void {
var mongoDb = 'mongodb://localhost/My_db';
mongoose.connect(mongoDb);
console.info("Connected to Mongo.")
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB Connection error'));
}
componentDidMount(){
this.setupDb()
}
render() {
return (<div></div> );
}
}
The error:
TypeError: mongoose__WEBPACK_IMPORTED_MODULE_1__.connect is not a
function
It looks like you're trying to connect to the database from the application frontend. You need to do this in the backend.
In your backend, make sure you run npm install mongoose. Once that is done, I think your code will execute without any problems. Alternatively, this is how I've done it:
var mongoose = require("mongoose");
const connect = () => {
mongoose.connect("mongodb://[username]:[password]#1[host]:[port]/[database]");
//e.g. "mongodb://My_db_user:pw1234#localhost:27017/My_db"
var db = mongoose.connection;
db.on("error", console.error.bind(console, "connection error:"));
db.once("open", function() {
console.log("Connected to mongo..")
});
};
Followed by a call to connect() somewhere in your startup script.
If you don't require any authentication for accessing your database, and you're running on the default port of 27017, you should be able to use your connection URI (mongodb://localhost/My_db).
package shipped to frontend by mongoose does not have the connect function.
you can only connect using a backend.
see here
Calling mongoose from react client side