How to render Next JS page on a custom Express server - reactjs

I am working on a NextJS project, and I need a form loaded on server, to be able to upload files so for that I used multer along with express in a custom server.
Now on GET request I want to render a specific page, but I am not sure how I can do this. I don't want to have any html in the server, just a call to the page. Is this even possible?
server.get('/', (req,res) => {
res.send(ReactDOMServer.renderToString(<myPage />))
});
when I start the server I am getting the following:
/Users/MONOLITH-Strat-Audrey/Projects/sandbox/multer-file-upload/server.js:41
res.send(ReactDOMServer.renderToString(<myPage />))
                                                                           ^
SyntaxError: Unexpected token <
In the server I am calling the page like this, which obviously doesn't work.
const myPage = require('./pages/index')
For references, this is my github with all the code.
Github Repo

There is a multipart error in your code.
Never import React components in server.js or node entry point file.
All pages should reside inside pages directory for Next.js to
parse it and serve.
Below are the changes made and it started working
Remove or comment below line from server.js
const myPage = require('./pages/index')
In line 48 - server.js
server.get('/',function(req,res){
// res.write(ReactDOMServer.renderToString(<myPage />))
return app.render(req, res, '/', query)
});
In your components/file.js render method return the jsx
class File extends Component {
render() {
return (<form action="/uploadfile" enctype="multipart/form-data" method="POST">
<input type="file" name="myFile" />
<input type="submit" value="Upload a file"/>
</form>)
}
}
References for custom server using Next.js
SSR in Next.js -
https://nextjs.org/docs/basic-features/pages#two-forms-of-pre-rendering
Next.js Custom server -
https://nextjs.org/docs/advanced-features/custom-server
Custom server example -
https://github.com/zeit/next.js/tree/canary/examples/custom-server

Related

How to server-side render a specific route in ReactJS?

I would like to server-side render only a specific route in React. For example, /home should be client-side rendered, but /post should be server-side rendered.
The /post route receives a post ID as a parameter(using react-router) and fetches the content from a database server.
Is their any way I can server-side render only a specific page/route using react-dom server?
Your data should be handled by the middleware and stored there to minimize api calls. The Front end should render based on that data.
One good approach is to use built version of your react within express.js server. So let's say you have your built version of your react inside build directory :
var express = require('express');
var app = express();
app.use("/post",function(req,res) {
console.log(req); // Do your stuff for post route
});
app.use("/",express.static(path.join(__dirname,"/build")));
app.use("/*",express.static(path.join(__dirname,"/build"))); // Handle react-router
const httpServer = require("http").createServer(app);
httpServer.listen(8080, function(){
console.log("Server is running on 8080");
});

Twitter login with React TypeError: Failed to fetch

I am running the React project on localhost:3000. I am trying to login with Twitter using React.
URL: http://localhost:3000/login/
<TwitterLogin
loginUrl="http://localhost:4000/api/v1/auth/twitter"
onFailure={this.onFailed}
onSuccess={this.onSuccess}
requestTokenUrl="http://localhost:4000/api/v1/auth/twitter/reverse"
/>
When I clicked the Twitter login icon. I keep getting the error "TypeError: Failed to fetch"
And for the console, I am getting the following error:
OPTIONS http://localhost:4000/api/v1/auth/twitter net::ERR_CONNECTION_REFUSED
I am also confused about what should I put for the Website URL and the Callback URL for the twitter developer settings. Please help. Thanks a lot!
Refere their doc
<TwitterLogin
//localhost:4000 endpoint should be your api running url
loginUrl="http://localhost:4000/api/v1/auth/twitter"
onFailure={this.onFailed}
onSuccess={this.onSuccess}
//your api endpoint
requestTokenUrl="http://localhost:4000/api/v1/auth/twitter/reverse"
/>
<TwitterLogin
loginUrl="http://<API-endpoint>/api/v1/auth/twitter"
onFailure={this.onFailed}
onSuccess={this.onSuccess}
//your api endpoint
requestTokenUrl="http://<API-endpoint>/api/v1/auth/twitter/reverse"
/>
Do not use localhost since you can get cors errors. See documentation for cors.
Try another package react-twitter-login
This Implementation not used any backend and created for simple OAuth with Twitter:
import React from "react";
import TwitterLogin from "react-twitter-login";
export default props => {
const authHandler = (err, data) => {
console.log(err, data);
};
return (
<TwitterLogin
authCallback={authHandler}
consumerKey={CONSUMER_KEY}
consumerSecret={CONSUMER_SECRET}
callbackUrl={CALLBACK_URL}
/>
);
};

Need help about nextjs dynamic url

I am having this problem that whenever i try to visit the page localhost:3000/blog/test directly it returns a 404 error. But whenever i try to visit it using <Link> component it works fine.
This is my code <Link href={{ pathname: '/blog', query: {slug: 'test'} }} as="/blog/test"><a className="nav__link">Blog</a></Link>
and i have a file blog.js in my pages folder.
What's happening is that on the client, with the Link component, you are creating a link to the blog.js page by setting "/blog" as the pathname.
When you go directly to the URL/blog/test, Next.js will try to render the page on the server and to do so will look for the file /pages/blog/test.js. That file doesn't exist, and Next.js doesn't know that you want to load the blog.js page and set query.slug to to the second part of the URL.
To do this, you need to map that route on the server to load the page you want, and pull the params you want out of the URL.
The Next.js docs cover this in Server Side Support for Clean URLs by using express to setup a custom server.
You can view the full code to get it working there, but your custom route will look something like this:
server.get('/blog/:slug', (req, res) => {
const actualPage = '/blog'
const queryParams = { slug: req.params.slug }
app.render(req, res, actualPage, queryParams)
})
You'll have to use now.json to set up your routes. Also it is important to note that it's now that builds the route so visiting it on the client side wont work if you are using localhost. Build your project with now and it should work.
Also the "as" parameter would be as={{ pathname:/user/manage/${variable}}}

Serve react without a need of index.html

Let's imagine i have a express server from where i can send react app file on browser request - app.js
fastify.route({
method: 'GET',
url: '/index.html',
handler: (req, res) => {
res.sendFile(app.js)
}
})
On client side i want browser to accept it as index.html with react inside.
import React from 'react'
import { render } from 'react-dom'
import App from './src/App'
// Where to place all html?
render(<App />, document.getElementById('someid'))
To put it simple, i want to get rid of index.html and generate it dynamically.
How can i do it?
Your react app is just a JavaScript bundle where as browser can only understand Html and execute js.
Browser parses HTML and creates DOM tree, during this process it fetches all the JavaScript in script tags. And React is not HTML.
So you have to send index.html for that matter any html file is must be sent to the browser first.

Refreshing a react router page that has a dynamic url/params

I have several components displayed with react router that have dynamic url paths. An example path I have is
<Route path="/newproject/:id" onEnter={checkSesh} component= {ProjectDetails} />
When entering this component, I have a componentWillMount function that extract the id part of the url so that I can get the info for the correct project and render it on the ProjectDetails component.
componentWillMount() {
var id = this.props.router.params.id
this.props.teamDetails(id);
}
this.props.teamDetails(id) this calls a redux action creator that will make an axios request to an express route that will get the project info from the database.
export function teamDetails(id) {
return function(dispatch) {
axios.get('/getteaminfo/' + id)
.then(res => {
dispatch({ type: "SET_TEAM_DETAILS", payload: {
teamInfo: res.data.teamInfo,
admin: res.data.admin,
adminID: res.data.teamInfo.teamAdmin,
teamMembers: res.data.teamInfo.teamMembers
}
})
});
}
}
everything works fine upon visiting the page after already being logged in etc. But when I refresh the page /newproject/:id, i get an error Uncaught SyntaxError: Unexpected token <. An example url in my browser looks like http://localhost:3000/newproject/58df1ae6aabc4916206fdaae. When I refresh this page, I get that error. The error is complaining about my <!DOCTYPE html> tag at the very top of my index.html for some reason. This index.html is where all of React is being rendered.
When page is refreshed store state is not preserved. Make sure the state is not important to load the page, or at least initialized properly every time.
For e.g. login information if saved in store and not on browser with localStorage or cookies etc.. then on refresh, the error will come when trying to access /getteaminfo/ route through axios. The response will have error html and it can't be parsed by js.
Please check your web console on for more information. You can use chrome extension like https://github.com/zalmoxisus/redux-devtools-extension which will show your store and etc..
Make sure to check what /getteaminfo/ gives with id is not passed.
Also, make sure on your server side, did you route requests to react-router path through something like this?
e.g. express js,
app.get('*', function response(req, res) {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
be sure to sendFile with the real location of index.html
I found the answer here: react-router dynamic segments crash when accessed I added <base href="/" /> into the <head>of my index.html. You can also read more info here: Unexpected token < error in react router component

Resources