Kirill
Kirill

Reputation: 53

Next JS Custom Server app.render do not pass query to a component

I'm trying to pass userData with app.render, but while Server side rendering router.query is empty, although i have passed userData! Is it NextJS's bug, or am i doing something wrong?

app.js:

const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')

const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare().then(() => {
  createServer((req, res) => {

    const parsedUrl = parse(req.url, true)
    const { pathname, query } = parsedUrl

    if (pathname === '/index') {
      app.render(req, res, '/index', {
        userData: {
          id: 1,
          name: 'admin'
        }
      })
    } else {
      handle(req, res, parsedUrl)
    }
  }).listen(3333, err => {
    if (err) throw err
    console.log('> Ready on http://localhost:3000')
  })
})

pages/index.js:

import { useRouter } from 'next/router'

export default () => {
    const router = useRouter();
    const { query } = router;

    return (
        <div>
            Query: {JSON.stringify(query)}
        </div>
    );
};

Upvotes: 5

Views: 3137

Answers (2)

Nico
Nico

Reputation: 7256

If getInitialProps is absent, Next.js will statically optimize your page automatically by prerendering it to static HTML. During prerendering, the router's query object will be empty since we do not have query information to provide during this phase. Any query values will be populated client side after hydration.

You can access your query using getInitialProps.
with useRouter:

import { useRouter } from 'next/router'
const Index = () => {
  const router = useRouter();
  const { query } = router;

  return (
      <div>
          Query: {JSON.stringify(query)}
      </div>
  );
};

Index.getInitialProps = async () => {
  return {};
};
export default Index

with a class component:

import React from 'react'

class Index extends React.Component {
      static async getInitialProps (context) {
        let query  = context.query;
        return {query}
      }

      render() {
        let {query} = this.props
        return (
          <div>
              Query: {JSON.stringify(query)}
          </div>
      );
      }
    }
export default Index  

Or if you prefer a functional component :

const Index = (props) => (
  <div>
    Query: {JSON.stringify(props.query)}
  </div>
)

Index.getInitialProps = async ( context ) => {
  let query  = context.query;
  return {query}
}

export default Index  

Please note that obviously this works with /index but not with /

Upvotes: 4

Leander
Leander

Reputation: 148

I think it's as simple as adding a return statement before app.render to prevent the rest of the code from executing.

if (pathname === '/index') {
  return app.render(req, res, '/index', {
    userData: {
      id: 1,
      name: 'admin'
    }
  })
} else {
  handle(req, res, parsedUrl)
}

Upvotes: 1

Related Questions