В NextJS как передать данные из server.js чтобы _app.js?

#javascript #node.js #reactjs #next.js

Вопрос:

В моем проекте NextJS, который я использую koa в качестве веб-фреймворка в server.js файле, я хочу сделать следующее,

  1. Выполните несколько внешних вызовов api, чтобы сгенерировать некоторые пользовательские данные для server.js каждого запроса,
  2. Затем передайте сгенерированные данные _app.js , чтобы данные могли быть доступны всем страницам с помощью реквизитов или контекстов.

Мой вопрос в том, как мы могли бы передать сгенерированные данные на server.js _app.js страницы или страницы?

Вот несколько примеров кода,

 //////////////////////////////////////////////////
// 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?
  ...
};
 

Причина, по которой я хочу сохранить custom_logic это внутри server.js , заключается в том, что,

  • Если name это не проверено, произойдет перенаправление, verifyNameFunc в которое будут введены некоторые данные verified_names .

Я не уверен, можно ли перенести _app.js и это перенаправление?

Комментарии:

1. Почему бы не переместить custom_logic то, что извлекает данные напрямую MyApp.getInitialProps ? Вам действительно нужно это делать на пользовательском сервере?

2. @juliomalves Отличный вопрос, позвольте мне сразу же обновить пост, чтобы показать, почему!

3. @juliomalves Обновил, в основном это связано с тем, что для создания пользовательских данных будут происходить некоторые перенаправления, я не уверен, можно ли их перенести _app.js .

4. Да, его можно перенести туда даже с перенаправлениями. Точно такой же код можно было бы использовать в getInitialProps .

5. Тогда, может быть, вам вообще не нужен пользовательский сервер? И вместо этого следует перенести всю логику _app .

Ответ №1:

Это всего лишь одно из решений: создайте отдельный файл js (модуль), в который вы экспортируете две функции setData() и getData() вот так:

 //////////////////////////////////////////////////
// ./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
};


 

Имейте в виду, что getInitialProps включение визуализации на стороне сервера на странице и позволяет выполнять начальное заполнение данных, это означает отправку страницы с уже заполненными данными с сервера (см. https://nextjs.org/docs/api-reference/data-fetching/getInitialProps).
Но, как вам было рекомендовано, возможно, вам вообще не нужен пользовательский сервер

Комментарии:

1. Я думаю, что меня смущает, нужен ли мне пользовательский сервер или нет. Насколько я понимаю, в next.js имеет встроенный сервер, но он в основном предназначен для рендеринга ssr, а для более продвинутых функций веб-сервера нам все равно нужно использовать такие вещи, как koa , нет?

2. Спасибо за ваш код! Один быстрый вопрос, setData и getData будет ли доступ к данным, и данные можно рассматривать как глобальный var? Или данные хранятся во внешней БД?

3. Ни в глобальном var, ни во внешней бд. setData фактически не будет указывать значение custom_data внутреннего значения обещания, которое, в свою очередь, используется в обычном модуле js. В своем решении я использовал две концепции: модули и обещания . Я надеюсь, что мой ответ поможет вам, и вы примете его

4. О koa себе : Я с этим не знаком, поэтому не могу сказать наверняка. Но если это просто другой сервер, то да, вы, вероятно, могли бы переработать свой код, чтобы избавиться от него. Это было бы лучше наверняка, потому что без пользовательского сервера вы получите некоторые дополнительные оптимизации от ‘Next.js» сама структура (см. nextjs.org/docs/advanced-features/custom-server )

5. Я вижу, спасибо за ваши комментарии

Ответ №2:

Вы можете использовать getInitialProps и выполнить перенаправление, __app.tsx если вам это нужно.

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

Кроме того, довольно легко проверить, проверено ли имя __app.tsx , а затем отобразить другого ребенка на основе этого. Я не думаю, что для этого вам нужен целый пользовательский сервер.

Также взгляните на https://nextjs.org/blog/next-10-2#routing-based-on-headers-and-query-string-parameters.