How to utilize server side data fetching in client side page.jsx
Answered
American Crocodile posted this in #help-forum
American CrocodileOP
Within the docs for data fetching, specifically the content on patterns. I couldn't recognise at least, a pattern that fit a modal whereby; the app will fetch data on the server and pass to all child components, similar to how a context component does.
In my example I am fetching data from google sheets useing fetch. I am then calling the function that does this in a parent page app/quiz/page.jsx.
I'm trying to move utilise next routing and features in general rather than relying on context.
I have three more pages nested within app/quiz that look similar to this in structure app/quiz/pagename/page.jsx
I would like to make the data fetched at app/quiz/page.jsx available to sub pages. To note, these pages will be client side.
I had set this up using context but ran into issues with the pattern, mainly where the data would be null until data was loaded. I know I can get around this but saw an opportunity to delve more into what Next provides.
Any guidance here adding to the docs would be extremely appreciated.
In my example I am fetching data from google sheets useing fetch. I am then calling the function that does this in a parent page app/quiz/page.jsx.
I'm trying to move utilise next routing and features in general rather than relying on context.
I have three more pages nested within app/quiz that look similar to this in structure app/quiz/pagename/page.jsx
I would like to make the data fetched at app/quiz/page.jsx available to sub pages. To note, these pages will be client side.
I had set this up using context but ran into issues with the pattern, mainly where the data would be null until data was loaded. I know I can get around this but saw an opportunity to delve more into what Next provides.
Any guidance here adding to the docs would be extremely appreciated.
Answered by Ray
// data.js
const getData1 = cache(async () => {})
const getData2 = cache(async () => {})
const getData3 = cache(async () => {})
// layout.js
export default async function Layout({children}) {
const data = await Promise.all([getData1,getData2,getData3])
return (
<>
{children}
</>
)
}
// app/quiz/pathname/page.jsx
export default async function Page() {
const data = await getData1()
...
}20 Replies
American CrocodileOP
For more context. Here's my app/quiz/page.jsx content.
import { fetchSheetData } from '../utils';
export default async function Page() {
const sheetData = fetchSheetData();
const data = await Promise.all(sheetData);
console.log( data );
return (
<>
{/* Quiz content here */}
</>
);
};I imagine I can do something like...
Though it didn't seem like I am understanding the Next way?
return React.cloneElement(children, { sheetData });Though it didn't seem like I am understanding the Next way?
@American Crocodile For more context. Here's my app/quiz/page.jsx content.
js
import { fetchSheetData } from '../utils';
export default async function Page() {
const sheetData = fetchSheetData();
const data = await Promise.all(sheetData);
console.log( data );
return (
<>
{/* Quiz content here */}
</>
);
};
try this first
const data = await Promise.all([sheetData]);I think you could use nested layout with this and fetch the data in
app/quiz/layout.js
app/quiz/pathname/page.tsx
layout.js and pass it to contextapp/quiz/layout.js
app/quiz/pathname/page.tsx
American CrocodileOP
Okay, so you think context is a good practice in this case? The return of the data is fine from the above. Thanks for the square brackets note.
Just been trying to figure if I can not use context
I read this and thought perhaps I should/could do it a different way
@American Crocodile Okay, so you think context is a good practice in this case? The return of the data is fine from the above. Thanks for the square brackets note.
yes you could do something like this
// layout.js
export default async function Layout({children}) {
const data = await fetchData()
return (
<Provider value={data}>
{children}
</Provider>
)
}
// app/quiz/pathname/page.jsx
'use client'
export default function Page() {
const data = useContext()
...
}@Ray yes you could do something like this
ts
// layout.js
export default async function Layout({children}) {
const data = await fetchData()
return (
<Provider value={data}>
{children}
</Provider>
)
}
// app/quiz/pathname/page.jsx
'use client'
export default function Page() {
const data = useContext()
...
}
American CrocodileOP
Thanks, this is the pattern I went with at first. All working. Just trying to up my Next understanding.
And, thought I could do it without using context/provider
@American Crocodile And, thought I could do it without using context/provider
yea you could do that without context but with caching.
American CrocodileOP
This is likely what I'm getting at yeah. What I couldn't get from this was though how to provide the nested pages with the data
@American Crocodile This is likely what I'm getting at yeah. What I couldn't get from this was though how to provide the nested pages with the data
// data.js
const getData1 = cache(async () => {})
const getData2 = cache(async () => {})
const getData3 = cache(async () => {})
// layout.js
export default async function Layout({children}) {
const data = await Promise.all([getData1,getData2,getData3])
return (
<>
{children}
</>
)
}
// app/quiz/pathname/page.jsx
export default async function Page() {
const data = await getData1()
...
}Answer
American CrocodileOP
This looks like the pattern. Thank you Ray, you're a legend
American CrocodileOP
To update this ticket.
Even with using cache. I was still in server components. My issue was determining the mental modal for how Next.js wants my to deal with fetching data in the context of using that data in a client-side component.
Next.js clearly states in the docs. Fetch = Sever.
Currently. I can't determine a way to directly pass data fetched by the server to a client component.
That being said, if I separate page from component I can achieve the desired result. For example; page.jsx to fetch data and within that page a separate component for the page which I pass the data to.
The issue here is it makes a very simple app start to gain a lot of components!
Am I missing something here?
Server fetch > pass to client component on render. Or do client components have to call a route to get data from the server and that is the best practice way to do it?
Even with using cache. I was still in server components. My issue was determining the mental modal for how Next.js wants my to deal with fetching data in the context of using that data in a client-side component.
Next.js clearly states in the docs. Fetch = Sever.
Currently. I can't determine a way to directly pass data fetched by the server to a client component.
That being said, if I separate page from component I can achieve the desired result. For example; page.jsx to fetch data and within that page a separate component for the page which I pass the data to.
The issue here is it makes a very simple app start to gain a lot of components!
Am I missing something here?
Server fetch > pass to client component on render. Or do client components have to call a route to get data from the server and that is the best practice way to do it?
American CrocodileOP
That's exactly what I've gone with. Starting to view pages as server components only, helps. They aren't, but using them that way is a good train of thought. I'm from server based languages so it's just wrapping my head around it. Also with a lot of information pertaining to how to do things can take time to figure out what Next wants.
Thanks again RAY