How to combine Component.getServerSideProps props and MyApp.getInitialState props? - next.js

Next.js has an App component. There is an App component in Next.js where I can change props for each component when it rendering:
export default function MyApp({ Component, pageProps }) {
// Here some actions with pageProps
return (
<React.Fragment>
<Component {...pageProps} />
</React.Fragment>
)
}
But if i want to use MyApp.getInitialProps:
MyApp.getInitialProps = async (appContext) => {
const appProps = await App.getInitialProps(appContext);
return { ...appProps }
}
Then in browser after console.log(props) i see only props, that i have with function Component.getServerSideProps.
But how can I combine in component props the props received via MyApp.getInitialProps and the props received via Component.getServerSideProps ?
P.S. It is not essential for me to use MyApp.getInitialState. GetServerSideProps will do too, the main thing is to combine the props

Related

How to use useState in root layout/page in app directory of nextjs 13

In Nextjs 13 - experimental app directory, if I wanted to use useState on the root layout/page I must add ‘use client’ to the code, which effectively prevents all nested components from being server components.. how can I work around this so that I can use useState and still have server components. Thanks to any responders.
I don't know if this answers to your question (it's better to add some example code to help users understand your problem)
If you create a Server Component, and in that component you add your Client Component, it works fine. For example
ClientComponent.tsx
"use client";
import {useState} from 'react';
export default function ClientComponent() {
const [count, setCount] = useState(0);
return (
<>
<h1>Client Component</h1>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</>
)
}
ServerComponent.tsx
async function getData(){
const res = await fetch('http://localhost:3000/api/hello');
return await res.json();
}
export default async function ServerComponent() {
const data = await getData()
return (
<>
<h1>Server Component</h1>
<p>{data.name}</p>
</>
)
}
Api hello.ts
export default async function handler(req, res) {
res.status(200).json({ name: 'John Doe' })
}
Your page
import ClientComponent from "./ClientComponent";
import ServerComponent from "./ServerComponent";
export default function Page() {
return(<>
<ClientComponent/>
<ServerComponent/>
</>
)
}
In this example ServerComponent is rendered on the server, but ClientComponent on the client so it maintain interactivity
Hope this will help

How to prevent duplicate initialState from client response in next-redux-wrapper?

I am using next redux wrapper in App.getInitialProps but in client response I get duplicated initialState are: initialState outside pageProps and inside pageProps, this happens everytime when navigate to another page. How can I fix it?
You can see the image below:
My code below:
function App({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
App.getInitialProps = wrapper.getInitialPageProps((store) => async (context) => {
if (context.req) {
const dataAuth = await fetchAuth(context);
// dispatch action auth to update data initialState
// this only running on the server-side
if (dataAuth) store.dispatch(authSlice.actions.setAuth(dataAuth));
else store.dispatch(authSlice.actions.resetAuth());
}
});

Next JS fetch data once to display on all pages

This page is the most relevant information I can find but it isn't enough.
I have a generic component that displays an appbar for my site. This appbar displays a user avatar that comes from a separate API which I store in the users session. My problem is that anytime I change pages through next/link the avatar disappears unless I implement getServerSideProps on every single page of my application to access the session which seems wasteful.
I have found that I can implement getInitialProps in _app.js like so to gather information
MyApp.getInitialProps = async ({ Component, ctx }) => {
await applySession(ctx.req, ctx.res);
if(!ctx.req.session.hasOwnProperty('user')) {
return {
user: {
avatar: null,
username: null
}
}
}
let pageProps = {}
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
return {
user: {
avatar: `https://cdn.discordapp.com/avatars/${ctx.req.session.user.id}/${ctx.req.session.user.avatar}`,
username: ctx.req.session.user.username
},
pageProps
}
}
I think what's happening is this is being called client side on page changes where the session of course doesn't exist which results in nothing being sent to props and the avatar not being displayed. I thought that maybe I could solve this with local storage if I can differentiate when this is being called on the server or client side but I want to know if there are more elegant solutions.
I managed to solve this by creating a state in my _app.js and then setting the state in a useEffect like this
function MyApp({ Component, pageProps, user }) {
const [userInfo, setUserInfo] = React.useState({});
React.useEffect(() => {
if(user.avatar) {
setUserInfo(user);
}
});
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<NavDrawer user={userInfo} />
<Component {...pageProps} />
</ThemeProvider>
);
}
Now the user variable is only set once and it's sent to my NavDrawer bar on page changes as well.
My solution for this using getServerSideProps() in _app.tsx:
// _app.tsx:
export type AppContextType = {
navigation: NavigationParentCollection
}
export const AppContext = createContext<AppContextType>(null)
function App({ Component, pageProps, navigation }) {
const appData = { navigation }
return (
<>
<AppContext.Provider value={appData}>
<Layout>
<Component {...pageProps} />
</Layout>
</AppContext.Provider>
</>
)
}
App.getInitialProps = async function () {
// Fetch the data and pass it into the App
return {
navigation: await getNavigation()
}
}
export default App
Then anywhere inside the app:
const { navigation } = useContext(AppContext)
To learn more about useContext check out the React docs here.

props passed to Page from getServerSideProps is always undefined

I'm using nextjs 9.3.5 and even the simplest example of getServerSideProps is always failing:
function Page({ data })
{
//Prints undefined
console.log(data);
return <div>Data in props: {data}</div>
}
export async function getServerSideProps()
{
var data = "Hello";
//Prints "Hello"
console.log(data);
return { props: { data } };
}
export default Page
This is basically a cut and paste from the very simple example on the nextjs website. getInitialProps works fine.
In case you added _app.js file into your project according official documentation you need add Component and pageProps inside, here is a minimal implementation of _app.js file.
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
I had the same problem and I realised that I was using getServerSideProps in the component that is not the actual page, rather it was my card component that I was displaying on the page.
This should be in the structure of your json that you are returning as a prop.
Try this:
export async function getServerSideProps() {
const data = {title:"Hello Sir"};
return { props: data }
}

When override _app.js what is getInitialProps used for?

what is this really do ?
pageProps = await Component.getInitialProps(ctx)
it looks "pageProps" this is just an empty object
import App, {Container} from 'next/app'
import React from 'react'
export default class MyApp extends App {
static async getInitialProps ({ Component, router, ctx }) {
let pageProps = {}
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx)
}
return {pageProps}
}
render () {
const {Component, pageProps} = this.props
return <Container>
<Component {...pageProps} />
</Container>
}
}
getInitialProps allows you to call out to get the props that you would like the component to have when rendered on the server.
For instance, I might need to display the current weather and I want Google to index my pages with that information for SEO purposes.
To achieve that, you'd do something like this:
import React from 'react'
import 'isomorphic-fetch'
const HomePage = (props) => (
<div>
Weather today is: {weather}
</div>
)
HomePage.getInitialProps = async ({ req }) => {
const res = await fetch('https://my.weather.api/london/today')
const json = await res.json()
return { weather: json.today }
}
export default HomePage
The line pageProps = await Component.getInitialProps(ctx) calls that initial function so that the HomePage component is instantiated with the initial props that result from that call to the weather API.

Resources