I'm experimenting with NextJs Custom Server using Express. And i noticed that on every request, getInitialProps gets called twice. When trying to find out what the problem is i stumbled upon React.Strictmode being the reason for that since it calls certain class methods and constructor twice to help debug. When setting it to false, the getInitialProps method gets called three times. NextJs "pages" folder routing is disabled.
To be mentioned that render() gets called twice or three times too.
My server.js :
require('dotenv').config();
const express = require('express');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const mongoose = require('mongoose');
const app = next({ dev });
mongoose.connect(process.env.DB_URI)
.then(()=>{
console.log('>Succesfully connected to the database');
app.prepare()
.then(() => {
const server = express();
server.listen(3000, (req, res) =>{
console.log('>Listening on port 3000');
});
server.get('*', (req, res)=>{
app.render(req, res, '/index', {something:true});
})
})
.catch((ex) => {
console.error(ex.stack);
process.exit(1);
})
})
.catch(e=>{
console.log('<!>Error connecting to database: \n' + e);
});
and my GetInitialProps:
static async getInitialProps(ctx){
console.log({...ctx.query});
console.log('once');
return {props:{...ctx.query}};
}
Console when Strictmode on:
{ something: true }
once
{ something: true }
once
Console when Strictmode off:
{ something: true }
once
{ something: true }
once
{ something: true }
once
Related
I am using a monorepo-styled build and I am struggling to get routes to hit properly. I am clicking my button:
const handleSubmit = () => {
console.log("button clicked");
axios.get('/', {
params: {
username: "John1904",
}
})
.then((res) => {
console.log(res.data);
});
};
And I am getting the index.ts file, which makes sense. When I attempt to use '/users or /users/, it doesn't work. I get
>GET http://localhost:3000/users?username=John1904 404 (Not Found)
>Uncaught (in promise) AxiosError {message: 'Request failed with status code 404'
This is in the browser console, while nothing else shows in my terminal.
My index.ts that is handling routes is:
const app: Express = express();
const port = process.env.PORT;
app.use(helmet());
app.use(cors());
app.use(express.json());
app.use('/users', usersRouter);
app.use('/', (_req, res) => res.status(200).send('Service online'));
app.use(errorHandler);
app.use(notFoundHandler);
And my server/src/routes/users/router.ts file is:
const router = express.Router();
router.get('/', async (_req: Request, res: Response) => {
try {
const items = await UserService.findAll();
res.status(200).send(items);
} catch (e) {
res.status(500).send(unwrapRouterErrorMessage(e));
}
});
So why is my request not going into the app.use('/users', usersRouter);?
Okay, thanks for asking about the ports, because I checked the URL requests in the dev tools and it was all going through to the frontend and not hitting the backend. Everything was going to the port 3000 instead of 3006. For now I hardcoded the route to go to http://localhost:3006/ and it worked. Thanks again.
///component
function Home() {
const [show, setShow]= useState([{name:'', info:'', airingDate:'', poster:''}])
useEffect(()=>{
fetch("/home")
//.then(res=> res.json())
.then(res => res.text())
.then(text => console.log(text))
})
return (
<div>
{show.map(a=>
<div>
<h2>{a.title}</h2>
</div>
)}
</div>
)
/////index.js
const TvShows = require("./models/TvShows");
const express = require("express");
const app = express();
const mongoose= require("mongoose")
const dotenv= require("dotenv");
const authRoute = require("./routes/auth");
const { application } = require("express");
const userRoute = require("./routes/users");
const commentRoute = require("./routes/comments");
const tvshowsRoute = require("./routes/tvshows");
const cors = require("cors");
app.use(cors());
console.log(".");
dotenv.config();
app.use(express.json());
mongoose.connect(process.env.MONGO_URL,{
useCreateIndex: true,
useNewUrlParser: true,
useUnifiedTopology: true,
}).then(console.log("connected to mongoDB"));
app.use("/auth", authRoute);
app.use("/users", userRoute);
app.use("/comments", commentRoute);
app.post("/api/home", tvshowsRoute);
app.use("/api/home", tvshowsRoute);
/*
app.get('/api/home', (req,res)=>{
TvShows.find().then((result)=>{
res.send(result);
})
})
*/
/*
app.use("/",(req,res)=>{
console.log("main url")
})*/
app.listen("3001",()=>{
console.log("backend running");
})
//////route
const router = require("express").Router();
const TvShows = require("../models/TvShows");
router.post("/api/home", async (req, res) => {
console.log("here")
try{
const newTvShow = new TvShows({
title: req.body.title,
poster: req.body.poster,
info: req.body.info
});
const savedTvShows = await newTvShow.save();
res.status(200).json(savedTvShows);
}catch (err) {
res.status(500).json(err);
}
}
);
router.route("/api/home").get((req, res)=>{
TvShows.find()
.then(foundShows=> res.json(foundShows))
})
module.exports = router;
when I change res.json with res.text I see my index.html page on console not the data I want to fetch from mongodb. This error is probably because I didn't use /api/ on root url but I couldn't figure it out where I should write it. I tried but didn't work. It would be so good if someone could've helped. Thank you so much.
Indeed, you are fetching the /home page of your front-end app.
Assuming the api is on a different server, you would need to call the address of that server.
If you have a set up locally with a nodejs server and a react app running separately, you should have them run on two different ports.
If you have react app on http://localhost:3000 (default), then change your api to listen on 3001, then in your react code above, you can use the full uri
http://localhost:3001/api/home
in your fetch call.
I'm making a lot of assumptions about how you have this set up, based on my own experience of local development for similar problems.
I have been looking all over to try and figure out why this doesn't work. I have two applications, a client and a server. I'd like to proxy the client requests to the server. I have a route called /api/repositories. I can't have the proxy in the package.json, because it needs to work in production, also.
It is a Create React App project. Here are the important files.
setupProxy.js
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = (app) => {
app.use(
createProxyMiddleware("/api", {
target: "http://my.server.com",
changeOrigin: true,
onProxyReq: (proxyReq) => {
console.log("logged");
if (proxyReq.getHeader("origin")) {
proxyReq.setHeader("origin", "http://my.server.com");
}
},
})
);
};
And I use it in a functional React component called Searchbar, as such:
Searchbar.js
import axios from "axios"
async function getRepos() {
const response = await axios({
method: "GET",
url: "/api/repositories",
});
return response.data;
}
function Searchbar() {
const [repos, setRepos] = useState([]);
// Get the repos on load
useEffect(async () => {
setRepos(await getRepos());
}, []);
return (
<div>
{repos.map((repo) => <p>{repo}<p>)}
</div>
);
}
However, when I run npm run start and run the development server, all of my API requests are going to http://localhost:3000/api/repositories, which obviously returns a 404 error. What am I doing wrong?
I'm doing development on Next.JS, and every time I hot reload after making a modification of the codes, there seems to be some kind of a cache that causes Client side codes and Server side codes to be different.
Currently, I need to open a new window every time I save my codes, in order to see the updates.
Is there anything I can do so it auto reload to the latest codes available all the time?
I tried using helmet/nocache with no results.
const express = require('express')
const next = require('next')
//const routes = require('./routes')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
const nocache = require('nocache') //added no cache
app.prepare()
.then(() => {
const server = express()
server.use(nocache()) //using no cache
server.get('/listing/:id', (req, res) => {
const actualPage = '/listing'
const queryParams = { id: req.params.id }
return app.render(req, res, actualPage, queryParams)
})
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(3000, '127.0.0.2', (err) => {
if (err) throw err
console.log('> Ready on http://localhost:3000')
})
})
.catch((ex) => {
console.error(ex.stack)
process.exit(1)
})
I'm using react.js and express.js and getting 404 error on my fetch request.
I'm simply trying to have my routes return testing express.js...
[app.js]
'use strict';
const NODE_ENV = process.env.NODE_ENV;
const PORT = process.env.PORT;
const next = require('next');
const express = require('express');
const api = require('./api');
const client = next({ dev: NODE_ENV === 'development' });
const clientHandler = client.getRequestHandler();
const app = express();
client.prepare().then(() => {
app.use('/api', api);
app.get('*', (req, res) => clientHandler(req, res));
});
const listener = app.listen(PORT, err => {
if (err) throw err;
console.log('listening on port: %d', listener.address().port); //eslint-disable-line
});
[/api/index.js]
'use strict';
const express = require('express');
const app = express();
app.get('/api/test', function (req, res) {
res.send('testing express.js...');
});
module.exports = app;
[Body.js]
import React from 'react';
export default class Body extends React.Component {
constructor(props) {
super(props);
this.fetchContacts = this.fetchContacts.bind(this);
}
componentDidMount() {
this.fetchContacts();
}
async fetchContacts() {
const res = await fetch('/api/test');
const contacts = await res.json();
log(contacts);
this.setState({ contacts });
}
render() {
return <div>hello world!</div>;
}
}
Question: Why am I getting a 404 error?
To make your /api/test route work properly, you need to change this:
app.get('/api/test', function (req, res) {
res.send('testing express.js...');
});
to this:
app.get('/test', function (req, res) {
res.send('testing express.js...');
});
Your router is already looking at /api so when you then put a route on the router for /api/test, you were actually making a route for /api/api/test. To fix it, make the above change.
Also, your index.js file should not be using an app object. It should be using an express.Router() object, though an app object is also a router so it might kind of work, but it's not the way it should be done.
That is not the way to load a react JS file on nodejs, follow this basic (React + NodeJS) guide:
https://blog.yld.io/2015/06/10/getting-started-with-react-and-node-js/#.Wd7zSBiWbyg
Or use "create-react-app" :
https://medium.com/#patriciolpezjuri/using-create-react-app-with-react-router-express-js-8fa658bf892d