Работая с Next.js, я пытаюсь сохранить данные в состоянии Context API после их извлечения в getInitialProps, чтобы исправить сверление реквизита.
Но поскольку getInitialProps - статический метод, мы не можем получить к нему доступ через this.context. Мне удалось сохранить их в componentDidMount, но в этом случае состояние контекста пусто при загрузке первой страницы, пока оно не заполнится. Не уверен, что лучше всего было бы в этом случае. В каком жизненном цикле я должен сохранять исходные данные в Context, чтобы они были сразу же, как при передаче props?
Не могу вспомнить, но я так не думаю. Я перешел на редукцию. Или еще лучше, если вы можете выполнять загрузку, пока данные не будут готовы.
Я решил это с помощью ContextApi прямо сейчас. Я собираюсь опубликовать пример.





you cannot use ContextAPI in Next.js server-side (SSR), because it's against hooks rules. https://reactjs.org/warnings/invalid-hook-call-warning.html
React сначала запустит getInitialProps, поэтому лучшее решение - получить данные оттуда и передать их через ваш компонент с помощью ContextAPI.
Давайте продолжим и посмотрим, как он работает, как показано ниже:
Реализуйте функции поставщика контекста, которые вы хотите передать через компоненты React.
В этом случае мы создадим наш глобальный поставщик контекста, обернув в него все приложение.
const AppProvider = ({ children }) => {
const [galleryData, setGalleryData] = React.useState([]);
const handleGalleryData = galleryData => {
setGalleryData(galleryData);
}
const contextProps = {
galleryData,
handleGalleryData
};
return (
<AppContext.Provider value = {contextProps}>
{children}
</AppContext.Provider>
);
}
<AppProvider>
<App />
</AppProvider>
И на свои страницы, например index.js, попробуйте так:
Index.getInitialProps = async (props) => {
const { req, res, query, ...others } = props;
// use your env variables, endpoint URIs
// ..
... fetch whatever you want..
const galleryProps = await fetch(endpoint); // isomorphic-unfetch
return {
galleryProps,
query,
...others
};
}
В зависимости от вашей версии Next.js вы можете использовать getServerSideProps вместо getInitialProps, но не забывайте вызывать его при каждом запросе.
Next.js will pre-render this page on each request using the data returned by getServerSideProps Data Fetching docs
Затем в своих компонентах вы можете проверить эти данные и сохранить их в ContextAPI.
const Index = props => {
const { galleryProps, query, ...others } = props;
const [galleryData, setGalleryData] = useState(galleryProps);
const { handleGalleryData, ...contextRest } = useContext(AppContext);
...
// Here you're going to store data into ContextAPI appropriatly.
useEffect(() => {
if (typeof galleryProps === 'object' && _.keys(galleryProps).length > 0) {
handleGalleryData(galleryProps);
}
}, [handleGalleryData]);
// Other times your page is loaded, you will GET this data from ContextAPI, instead of SSR props.
useEffect(() => {
if (_.keys(galleryDataProps).length <= 0 && _.keys(contextRest.galleryData).length > 0) {
setGalleryData(contextRest.galleryData);
}
}, []);
....
return (
<div>
{JSON.stringify(galleryData)}
</div>
);
Приведенный выше вариант использования не самый лучший, но он дает понимание того, как все работает с ContextAPI в приложениях Next.js. Я объясню это ниже:
Первый useEffect() проверяет, получил ли компонент объект данных от реквизита, хранящего его через ContextAPI.
Второй проверяет, есть ли в магазине какие-то данные.
You may fetch data in SSR mode over
getInitialPropsbefore your component loads.
Это хороший пример, который я сейчас ищу, так что можете ли вы привести пример в codeandbox (или любой другой) ссылку с вышеупомянутой реализацией в реальном времени, которая будет полезна .. И я также сомневаюсь, следует ли реализовать redux или context api в nextjs 9 для управления состоянием. Не могли бы вы объяснить и это?
Конечно, но я пробую что-то получше, поэтому я могу переопределить serverRuntimeConfig на своих страницах.
Я начинаю с next.js, поэтому я ожидаю начать с хорошей структуры проекта, а также с управления состоянием .. Так что я надеюсь продолжить с примером ссылки, которую вы предоставляете, поэтому, пожалуйста, дайте мне обновленное решение с хорошим примером .. Спасибо заблаговременно..
Я только что обновил свое решение, так что вы можете его проверить. Это так просто, чем в документации React. Попробуйте. Хорошего кода! :))
@GMaiolo, это тот же подход, но getServerSideProps будет вызываться при каждом запросе.
Можете ли вы предоставить codeandbox или jsfiddle рабочий пример
Привет, @Vash, вот официальный пример Next.js с Context-API: github.com/vercel/next.js/tree/canary/examples/with-context- api
Когда вы говорите о getInitialProps, вы имеете в виду Server Sider Render (SSR). Если вам не нужно выполнять SSR, достаточно примера в Далее с Context API, в противном случае вы можете использовать pageProps в файле _app.js для инициализации своего контекста, подробнее о пользовательском приложении читайте в документации Пользовательское приложение
Note: If you're using Next.js 9.3 or newer, we recommend that you use getStaticProps or getServerSideProps instead of getInitialProps.
import { AppProvider } from '../contexts/AppProvider';
function MyApp({ Component, pageProps }) {
return (
<AppProvider initialData = {pageProps?.initialData}>
<Component {...pageProps} />
</AppProvider>
);
}
export default MyApp;
Затем вы можете инициализировать свой контекст данными, полученными сервером.
import { useState, createContext, useMemo } from 'react';
export const AppContext = createContext();
export const AppProvider = ({ children, initialData }) => {
const [data, setData] = useState(initialData);
const value = useMemo(() => ({ data, setData }), [data]);
return <AppContext.Provider value = {value}>{children}</AppContext.Provider>;
};
Но подождите !!, как мы можем получить данные с сервера Страницы? Это может немного сбивать с толку, но pageProps, полученные со страницы с getServerSideProps, всегда передаются через MyApp, а затем в дочерний компонент.
getServerSideProps (in Page) ===> MyApp({ Component, pageProps }) ===> Page({pageProps})
И вот как будет выглядеть Пейдж в контексте. В первый раз Сервер отображает страницу и инициализирует контекст, а затем вы можете получить данные или обновить контекст снова.
import { useContext } from 'react';
import { AppContext } from '../contexts/AppProvider';
export default function Index() {
const { data, setData } = useContext(AppContext);
const handleOnClick = () => {
setData(`Data from client: ${Date.now()}`);
};
console.info(data);
return (
<div>
<div>{JSON.stringify(data)}</div>
<button onClick = {handleOnClick}>Update Context</button>
</div>
);
}
export function getServerSideProps() {
const data = `Data from server: ${Date.now()}`;
return {
props: {
initialData: data,
},
};
}
Вы можете проверить, отображается ли console.info(data); на консоли сервера и клиента, но только на клиенте.
Вы решили этот вопрос?