简体   繁体   中英

In NextJS how to pass data from server.js to _app.js?

In my NextJS project, I'm using koa as the web framework in server.js file, what I want to do is as follows,

  1. Do some external api calls to generate some custom data in server.js per each request,
  2. Then pass the generated data to _app.js , so that the data could be shared by all pages via props or contexts.

My question is how could we pass the data generated in server.js to _app.js or pages?

Here are some code examples,

//////////////////////////////////////////////////
// server.js
import Koa from "koa";
import Router from "koa-router";

const verified_names = {};
const handle = app.getRequestHandler();  // NextJS use this to handle each request

app.prepare().then(async () => {
  const server = new Koa();
  const router = new Router();
  ...

  // in verifyNameFunc, if name is verified, will set verified_names[name] = some_data
  router.get("/verify_name", verifyNameFunc);

  router.get("(.*)", async (ctx) => {
    // custom logic starts here: if name is not verified, redirect to /verify_name
    const name = ctx.query.name;
    if (verified_names[name] === undefined) {
        ctx.redirect(`/verify_name?name=${name}`);
    }
    // HERE: do some external api calls and generate some data
    var custom_data = custom_logic(verified_names[name]);

    // I think here starts rendering the pages (i.e. enters the execution of `_app.js` and pages)
    // QUESTION: how to pass the above `custom_data` to _app.js or pages?
    await handle(ctx.req, ctx.res);  
    }
  });

  server.use(router.routes());
  server.listen(...);
  
});

//////////////////////////////////////////////////
// _app.js

class MyApp extends App {
  ...
}

MyApp.getInitialProps = async ({ ctx }) => {
  // Can we get the `custom_data` from server.js here?
  ...
};

The reason why I want to keep the custom_logic inside server.js is that,

  • If name is not verified, a redirect would happen and verifyNameFunc will set some data into verified_names .

I'm not sure if this redirect could be moved into _app.js as well?

It's just one of solutions: Create a separate js file (module), where you will export two functions setData() and getData() like this:

//////////////////////////////////////////////////
// ./lib/data-manager.js

let promiseResolver = undefined;
const promise = new Promise((resolve) => {
  promiseResolver = resolve;
})

export function setData(data) { promiseResolver(data); }
export function async getData() { return promise; }

//////////////////////////////////////////////////
// server.js
import { setData } from "../lib/data-manager"
import Koa from "koa";
import Router from "koa-router";

const verified_names = {};
const handle = app.getRequestHandler();  // NextJS use this to handle each request

app.prepare().then(async () => {
  const server = new Koa();
  const router = new Router();
  ...

  // in verifyNameFunc, if name is verified, will set verified_names[name] = some_data
  router.get("/verify_name", verifyNameFunc);

  router.get("(.*)", async (ctx) => {
    // custom logic starts here: if name is not verified, redirect to /verify_name
    const name = ctx.query.name;
    if (verified_names[name] === undefined) {
        ctx.redirect(`/verify_name?name=${name}`);
    }
    // HERE: do some external api calls and generate some data
    var custom_data = custom_logic(verified_names[name]);

    setData(custom_data); // <-- saving data

    // I think here starts rendering the pages (i.e. enters the execution of `_app.js` and pages)
    // QUESTION: how to pass the above `custom_data` to _app.js or pages?
    await handle(ctx.req, ctx.res);  
    }
  });

  server.use(router.routes());
  server.listen(...);
  
});

//////////////////////////////////////////////////
// _app.js
import { getData } from "../lib/data-manager"

class MyApp extends App {
  ...
}

MyApp.getInitialProps = async ({ ctx }) => {
  const custom_data = await getData();  // <-- getting data
};


Keep in mind that getInitialProps enables server-side rendering in a page and allows you to do initial data population, it means sending the page with the data already populated from the server (See https://nextjs.org/docs/api-reference/data-fetching/getInitialProps ). But, as it was recommended to you, maybe you don't need custom server at all

You can use getInitialProps and do the redirect in __app.tsx if you need to.

https://nextjs.org/docs/api-reference/data-fetching/getInitialProps

Also it's rather easy to check if a name is verified in __app.tsx and then to render a different child based on that. I don't think you need an entire custom server for that.

Also take a look at https://nextjs.org/blog/next-10-2#routing-based-on-headers-and-query-string-parameters .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM