Next JS with react-intl creates an ancestry issue - reactjs

I'm trying to setup NEXT Js with react-intl.
I've added to my _app.tsx the setup for react-intl as follows:
import { IntlProvider } from 'react-intl';
import English from "../../lang/compiled-locales/en-US.json"
import French from "../../lang/compiled-locales/fr.json"
import configs from '../../configs';
// https://itnext.io/next-js-react-intl-add-internationalisation-to-your-nextjs-app-4f933104b1f7
const MyApp = ({ Component, pageProps }: AppProps) => {
const { locale } = useRouter()
const messages = useMemo(() => {
switch (locale) {
case "fr":
return French
default:
return English
}
}, [locale])
return <IntlProvider
locale={locale || configs.languages.default}
messages={messages}>
<Component {...pageProps} />
</IntlProvider>
}
export default MyApp
When I ran it, it worked like a charm, but when I do a page reload, I get the following error:
Server Error
Error: [React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.
This error happened while generating the page. Any console logs will be displayed in the terminal window.
I'm guessing it's something to do with SSR but no idea how to fix. Thank you in advance for your help.
Here is the sample usage in my pages/index.tsx
import type { NextPage } from 'next'
import Head from 'next/head'
import { FormattedMessage } from 'react-intl'
import Header from '../components/Header'
const Home: NextPage = () => {
return <div className="">
<Head>
<title><FormattedMessage defaultMessage="FlipFlip - Print your videos for real!" id="landing.seo.title" /></title>
</Head>
<Header />
</div>
}
export default Home

Related

problem in my header with nextjs i18n in 404 page

I have a problem with nextjs i18n
I have 4 languages and when I change them everything is correct but on page 404 my header and content are wrong
anyone can help me?
_app.js
import { appWithTranslation } from "next-i18next";
import Header from "../components/Header";
import "../styles/globals.css";
function MyApp({ Component, pageProps }) {
let index = 2;
return (
<div dir={index === 1 ? 'rtl' : 'ltr'}>
<Header />
<Component {...pageProps} />
</div>
);
}
export default appWithTranslation(MyApp);
and index.js
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import { useTranslation } from "next-i18next";
import MainPage from "../components/MainPage";
export default function Home() {
return (
<main>
<MainPage />
</main>
);
}
export async function getStaticProps({ locale }) {
return {
props: {
...(await serverSideTranslations(locale, [
"common",
"newsletter", // Add newsletter translations
"built-in-demo", // Add the built-in demo translations
"navbar"
])),
// Will be passed to the page component as props
},
};
}
and app structure is :
nextjsapp
.next
components
locales
node_modules
pages
404.js
index.jsx

document is not defined when creating new portal in Nextjs

in my project I want to separate section like menu in header tag, content in main tag and contact in footer tag _document.js file, for this I created a new portal but I get an error document is not defined in my Header.js file.
I trying to create new portal in nextjs like this:
import React, { Fragment } from "react";
import ReactDOM from "react-dom";
import NavigationBar from "./NavigationBar";
import classes from "./header.module.css";
const Header = (props) => {
return (
<Fragment>
{ReactDOM.createPortal(
<NavigationBar>{props.children}</NavigationBar>,
document.getElementById("header")
)}
</Fragment>
);
};
export default Header;
I created _document.js:
import Document, { Html, Head, Main, NextScript } from "next/document";
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
return { ...initialProps };
}
render() {
return (
<Html lang="en" dir="ltr">
<Head />
<body>
<header id="header"></header>
<Main />
<footer id="_footer"></footer>
<div id="_modal"></div>
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
The error is thrown because document is only available inside the browser and not on the server. Next js executes this code on the server side and that's why the error is thrown.
You can wrap our code inside an if statement. If you check on the console the type of window it returns object. The following code illustrates this:
if (typeof window === 'object') {
// Check if document is finally loaded
}
Use React portal maker:
import React from "react";
import reactDom from "react-dom";
const Header = (props) => {
const content = <NavigationBar>{props.children}</NavigationBar>;
if (typeof window === "object") {
return reactDom.createPortal(content, document.getElementById("__header"));
}
return null;
};
export default Header ;

React render instagram feeds from data.json

I"m trying to render username comments with likes and a like. please see image on demo.
All of this comes form data.json
I can't find a way to display the json properly on the tags. What am I missing here?
Sorry I'm trying my best here with react as I'm quite a beginner.
demo
my index.js
import React from "react";
import styles from "./styles";
import { getCaptionFromEdges } from "./helpers";
const Posts = (props) => {
const { data } = props;
return (
<img src={data.owner.profile_pic_url} /> // this tag works
<p>{data.owner.node.username}</p> // this tag doesn't work
<hr>
//here I should display all comments with its like.
<p>{data.node.text}</p>// this doesn't work
);
};
export default Posts;
You need to wrap your elements with another element (or a Fragment). Try the following:
import React from "react";
import styles from "./styles";
import { getCaptionFromEdges } from "./helpers";
const Posts = (props) => {
const { data } = props;
return (
<>
<img src={data.owner.profile_pic_url} />
<p>{data.owner.node.username}</p>
<hr />
<p>{data.node.text}</p>
</>
);
};
export default Posts;

How to provide context from contextApi for a specific set of routes in nextjs and preserve state with routing through linking?

I am using contextApi with nextjs and I'm having some trouble when providing a context just for certain routes. I am able to make the context available for just a few routes, but when I transition from one to the other through linking, I end up losing the state of my application.
I have three files inside my pages folder:
index.tsx,
Dashboard/index.tsx and
SignIn/index.tsx.
If I import the provider inside the files Dashboard/index.tsx and SignIn/index.tsx and go from one page to the other by pressing a Link component from next/link, the whole state is set back to the initial state.
The content of the Dashboard/index.tsx file
import React from 'react';
import Dashboard from '../../app/views/Dashboard';
import { AuthProvider } from '../../contexts/auth';
const Index: React.FC = () => (
<AuthProvider>
<Dashboard />
</AuthProvider>
);
export default Index;
This is the contend of the SignIn/index.tsx file:
import React from 'react';
import SignIn from '../../app/views/SignIn';
import { AuthProvider } from '../../contexts/auth';
const Index: React.FC = () => (
<AuthProvider>
<SignIn />
</AuthProvider>
);
export default Index;
The views folder is where I create the components that will be rendered.
The content of the file views/SignIn/index.tsx is:
import React, { useContext } from 'react';
import Link from 'next/link';
import { AuthContext } from '../../../contexts/auth';
const SignIn: React.FC = () => {
const { signed, signIn } = useContext(AuthContext);
async function handleSignIn() {
signIn();
}
return (
<div>
<Link href="Dashboard">Go back to Dashboard</Link>
<button onClick={handleSignIn}>Click me</button>
</div>
);
};
export default SignIn;
And the content of the file views/Dashboard/index.tsx is:
import React, { useContext } from 'react';
import Link from 'next/link';
import { AuthContext } from '../../../contexts/auth';
const Dashboard: React.FC = () => {
const { signed, signIn } = useContext(AuthContext);
async function handleSignIn() {
signIn();
}
return (
<div>
<Link href="SignIn">Go back to sign in page</Link>
<button onClick={handleSignIn}>Click me</button>
</div>
);
};
export default Dashboard;
I am able to access the context inside both /Dashboard and /SignIn, but when I press the link, the state comes back to the initial one. I figured out that the whole provider is rerenderized and therefore the new state becomes the initial state, but I wasn't able to go around this issue in a "best practices manner".
If I put the provider inside _app.tsx, I can maintain the state when transitioning between pages, but I end up providing this state to the / route as well, which I am trying to avoid.
I was able to go around this by doing the following, but it really does not seem to be the best solution for me.
I removed the Providers from Pages/SignIn/index.tsx and Pages/Dashboard/index.tsx and used the following snippet for the _app.tsx file:
import React from 'react';
import { AppProps } from 'next/app';
import { useRouter } from 'next/router';
import { AuthProvider } from '../contexts/auth';
const App: React.FC<AppProps> = ({ Component, pageProps }) => {
const router = useRouter();
const AuthProviderRoutes = ['/SignIn', '/Dashboard'];
return (
<>
{AuthProviderRoutes.includes(router.pathname) ? (
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
) : <Component {...pageProps} />}
</>
);
};
export default App;
Does anyone have a better solution?

How can I use Keycloak in Next.js?

I'm trying to authenticate in Keycloak in Next.js using #react-keycloak/nextjs but once I pass the login it keeps sending me back to the Keycloak server and returning to the main page until it gives me an error because my token key is expired.
This is my _app.js:
import { ApolloProvider } from '#apollo/react-hooks'
import CssBaseline from '#material-ui/core/CssBaseline'
import { ThemeProvider } from '#material-ui/core/styles'
import { Persistors, SSRKeycloakProvider } from '#react-keycloak/nextjs'
import Layout from 'components/layout/Layout'
import { useApollo } from 'lib/apolloClient'
import KeycloakLoading from 'components/KeycloakLoading'
import {
keycloakCfg,
keycloakProviderInitConfig,
onKeycloakLogout,
onKeycloakTokens,
} from 'lib/keycloak'
import Head from 'next/head'
import PropTypes from 'prop-types'
import React from 'react'
import theme from 'styles/theme'
import 'leaflet/dist/leaflet.css'
import 'react-leaflet-markercluster/dist/styles.min.css'
import 'styles/styles.css'
import 'styles/animations.css'
import '../styles/globals.css'
// export function reportWebVitals(metric) {
// // These metrics can be sent to any analytics service
// console.log(metric)
// }
export default function MyApp(props) {
const { Component, pageProps, cookies } = props
const apolloClient = useApollo(pageProps.initialApolloState)
React.useEffect(() => {
// Remove the server-side injected CSS.
const jssStyles = document.querySelector('#jss-server-side')
if (jssStyles) {
jssStyles.parentElement.removeChild(jssStyles)
}
}, [])
return (
<React.Fragment>
<Head>
<title>My page</title>
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width"
/>
</Head>
<ThemeProvider theme={theme}>
<CssBaseline />
<SSRKeycloakProvider
keycloakConfig={keycloakCfg}
persistor={Persistors.Cookies(cookies)}
initConfig={keycloakProviderInitConfig}
onTokens={onKeycloakTokens}
onAuthLogout={onKeycloakLogout}
LoadingComponent={
<React.Fragment>
<KeycloakLoading />
</React.Fragment>
}
>
<ApolloProvider client={apolloClient}>
<Layout>
<Component {...pageProps} />
</Layout>
</ApolloProvider>
</SSRKeycloakProvider>
</ThemeProvider>
</React.Fragment>
)
}
MyApp.propTypes = {
Component: PropTypes.elementType.isRequired,
pageProps: PropTypes.object.isRequired,
cookies: PropTypes.any,
}
And this is my Keycloak configuration
export const keycloakCfg = {
realm: APP_CONSTANTS.KEYCLOAK_REALM,
url: `${APP_CONSTANTS.KEYCLOAK_HOST}/auth`,
clientId: APP_CONSTANTS.KEYCLOAK_CLIENT_ID,
}
export const keycloakProviderInitConfig = {
onLoad: 'login-required',
}
If anyone could point out what is wrong or alternatively tell me another way to use Keycloak in next.
React-keycloak/nextjs is deprecated in favor of react-keycloak/ssr. I followed the examples here: https://www.npmjs.com/package/#react-keycloak/ssr and was able to fully authenticate without issue.
I'm not sure what is causing your looping issues but it doesn't look like you are using the required cookie parser or passing them into the props via getInitialProps so that may be a good place to start.
An alternative would be:
Next-Auth has implemented a keycloak provider which would make your life much easier protecting both Frontend and Backend. Just specify keycloak options/configs in _app.js and you all set.
import {signOut, getSession, useSession } from 'next-auth/react';
export default function Home() {
let session = useSession();
console.log(session);
return (
<div >
<button onClick={() => {
console.log(session);
signOut();
console.log(session);
}}> Sign Out </button>
<h1>H1 test</h1>
</div>
)
}
export const getServerSideProps = async (ctx) => {
const backendSession = await getSession(ctx)
console.log(backendSession);
return {
props: {
}
}
}

Resources