#next.js
Вопрос:
Я использую getServerSideProps для получения подробной информации о событии. Я понимаю, что эти данные будут извлечены на сервере, затем произойдет какая-то предварительная обработка, а затем объект контекста будет передан в _document.js. Я знаю _document.js будет отображаться при каждом запросе, но я хотел бы добавить имя класса в свой html, если эти данные сервера присутствуют (чтобы предотвратить мигание при выполнении этой клиентской стороны).
Вот моя функция getServerSideProps:
export async function getServerSideProps(context) {
const shortId = context.params.short_id
const event = await GETrequest({ endpoint: API_PUBLIC_EVENT({ shortId }) })
return {
props: {
event,
shortId
} // will be passed to the page component as props
}
}
Когда я нахожусь внутри _document.js, Я могу видеть, что результаты моих getServerSideProps доступны, как видно, когда я регистрирую контекст в getInitialProps, как это:
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
console.log(initialProps)
// can see html that has been processed using my data
}
...
Я могу придумать несколько хитрых решений для получения моего имени класса в этом initialProps.html, но мне интересно, есть ли более простой способ.
Есть ли способ структурировать это так, чтобы мои данные были более легко доступны в _document.js, передано из getServerSideProps()?
Комментарии:
1. Next.js пользовательский
_document
не поддерживает методы извлечения данных , такие какgetStaticProps
илиgetServerSideProps
. Вместо этого вам следует перенести эту логику в свой обычай_app
.
Ответ №1:
Вот простой способ получить getServerSideProps()
данные вашей страницы в свой _document.js
, прежде чем приложение будет загружено.
Итак, как я уже упоминал, вы можете сделать некоторые забавные вещи с предварительно созданным html-кодом, который используется для использования данных getServerSideProps (). Это халтурное решение и очень ненадежное. Однако в моем случае я просто добавляю имя класса, не являющееся следствием, в свой документ (с защитой от сбоев на интерфейсе), так что даже если это не удастся, все будет в порядке.
Будьте очень осторожны, если вы решите использовать это.
Вот как это работает:
У меня есть getServerSideProps() на странице. В этой функции я извлекаю событие и передаю его в свой компонент страницы. В этом компоненте я добавляю пустой div, который, как я знаю, будет отображаться, добавляя необходимую мне информацию. Эта информация поступила от моего getServerSideProps().
<div data-meta-event-theme={event?.theme?.preset}></div>
// let's say theme preset = light
Затем в моей _document.js
getInitialProps(ctx)
функции я сначала проверяю , является ли это запросом сервера. Если это не так, пропустите (в противном случае сборка завершится неудачно). Затем я проверяю, поступает ли запрос с соответствующего маршрута. Мой маршрут структурирован так /j/[shortId]
, и это единственная используемая страница /j/
. Поэтому, прежде чем сработает какая-либо логика, я проверяю, чтобы убедиться, что мы на правильной странице.
const isInviteScreen = ctx.req.url.indexOf('/j/') > -1
Если мы находимся на нужной странице, то мы можем проанализировать значение из нашего html-кода и делать с ним все, что захотим.
if (isInviteScreen) {
const html = initialProps.html
// whatever you set your data to in the html
// make sure to keep the opening quote "
const key = 'data-meta-event-theme="'
// you don't have to touch this
const begin = html.indexOf(key)
const sub = html.substring(begin key.length)
const closingQuote = sub.indexOf('"')
const value = sub.substring(0, closingQuote)
console.log(value)
// logs 'light'
}
На данный момент я могу добавить это значение в качестве имени класса в свой html-код, и вуаля!, больше не мигает.
Вот более полная _document.js
:
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
// Make sure this operation is on the server and has a request
if (ctx.req) {
// Make sure we're only doing this for the correct route
const isInviteScreen = ctx.req.url.indexOf('/j/') > -1
if (isInviteScreen) {
const html = initialProps.html
// Your HTML key here, make sure to keep quote
const key = 'data-meta-event-theme="'
// Don't have to touch this
const begin = html.indexOf(key)
const sub = html.substring(begin key.length)
const closingQuote = sub.indexOf('"')
// Value that was sent from the page with getServerSideProps()
const value = sub.substring(0, closingQuote)
return {
...initialProps,
preference: { theme: value }
}
}
}
// Default return just in case
return {
...initialProps,
preference: { theme: 'light }
}
}
render() {
const theme = this.props.preference.theme
return (
<Html data-theme={theme} className={theme} lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
Поскольку эти данные кажутся несколько доступными между ними, я надеюсь, что есть более официальный способ сделать это?