Comments (14)
how is pagination solved for the examples above? or is it not resolved?
I ended up getting it all to work like this:
const storyblokApi = useStoryblokApi()
const { data } = await useAsyncData(
`blog-list-${locale.value}-${page.value}`,
async () => await storyblokApi.get('cdn/stories', {
version: draft,
starts_with: 'blog',
is_startpage: false,
language: locale.value,
per_page: 10,
page: page.value
})
)
You need to set a unique key for the cache to retrieve the data per page, so:
`blog-list-${locale.value}-${page.value}`,
is adding the page.value
string (e.g. '1') to the key of the cached data for that page. If you aren't using localization, then don't add locale.value
to the key.
and blog-list
is just arbitrary so you can name yours however you want.
from storyblok-nuxt.
you should be able to simply use storyblokApiInstance.getAll()
(instead of get()
) to get all stories without the need of any pagination-handling. the function directly returns the stories-array though - so rs
will be the finished array instead of rs.data.stories
.
here is how i do it ( using useState
instead of useAsyncData
and with multilanguage):
const articles = useState<NewsArticle[]>('articles-' + currentLocale.value)
if (!articles.value) {
const stories = await storyblokApi.getAll('cdn/stories', {
starts_with: 'articles/',
sort_by: 'first_published_at:desc',
language: currentLocale.value,
})
articles.value = stories
}
from storyblok-nuxt.
Thank you big time @bocooper-dev @codeflorist !!
I ended up implementing it this way:
/**
* Fetches Storyblok stories based on the provided URL or configuration.
*
* @param {string | StoryConfig} url - The URL or Storyblok configuration to fetch the story.
* @param {ISbStoriesParams} apiOptions - Additional API options for fetching the story (optional).
* @returns {Promise<ISbStoryData[]>} - The fetched story data.
*/
export async function useStoryblokGetStoriesAsync(
url: string,
apiOptions: ISbStoriesParams = {},
): Promise<ISbStoryData[]> {
const version = getStoryVersion()
const cv = getCacheVersion()
// @ts-expect-error: Nuxt doesn't offer an explicit export for useState and auto imports it.
const stories = useState<ISbStoryData[]>(`${cv}${url}`)
const storyblokApiInstance = useStoryblokApi()
if (!stories.value) {
const rs = await storyblokApiInstance.getAll('cdn/stories', {
version,
cv,
excluding_fields: apiOptions.excluding_fields || 'pageBody',
...apiOptions,
})
stories.value = rs
}
return stories.value
}
This worked fine on dev environment, tho I am getting 429 Your rate limit has been reached...
errors when building for Prod (when building prerender routes). But I am not sure the problem is related to the code here.
I will also try the suggestion in the link
from storyblok-nuxt.
I just played around with the existing composable useAsyncStoryblok and changed
to use either data.story or data.stories by changing it to story.value = data.story ?? data.stories;
Calling it like that
const news = await useAsyncStoryblok('', { version: 'draft', starts_with: 'news/' })
from storyblok-nuxt.
you can wrap your call to the storyblok-api inside a useAsyncData
call, so it get's stored in Nuxt's payload:
const articles = ref(null)
const storyblokApi = useStoryblokApi()
const { data } = await useAsyncData(
'articles',
async () =>
await storyblokApi.get('cdn/stories', {
version: 'draft',
starts_with: 'blog',
is_startpage: false,
})
)
articles.value = data.stories
but i agree, that a shorthand composable would be very handy.
from storyblok-nuxt.
Hi @papoms & @codeflorist, thanks for opening and giving insights into this feature request.
I will talk about this internally with my manager, but in the meantime, will you be willing to participate in developing the composable if we have the green light?
from storyblok-nuxt.
you can wrap your call to the storyblok-api inside a
useAsyncData
call, so it get's stored in Nuxt's payload:const articles = ref(null) const storyblokApi = useStoryblokApi() const { data } = await useAsyncData( 'articles', async () => await storyblokApi.get('cdn/stories', { version: 'draft', starts_with: 'blog', is_startpage: false, }) ) articles.value = data.storiesbut i agree, that a shorthand composable would be very handy.
@codeflorist With this your data object is structured a bit differently: data.value.data.stories
I thought this would work for me but I've run into a few problems over the past few weeks. Potentially cache related? Here are my problems:
- The page shows hydration errors on page refresh. You can even see the blog cards double in quantity with ugly broken CSS.
- i18n does not update on refresh, which I was able to fix by breaking out of SSG by passing a unique key to
cv
to invalidate cache. - When calling the same stories on different pages (like a recent blog component vs all blogs on the blog home page), nuxt would serve me the 3 cached articles from the recent blog component when I wanted all of them on the blog home page. This too was mitigated by cache invalidated at the expense of SSG.
// RecentArticles.vue
<script setup>
defineProps({ blok: Object })
const articles = ref(null)
const storyblokApi = useStoryblokApi()
const { data } = await useAsyncData(
'recent-articles',
async () =>
await storyblokApi.get('cdn/stories', {
version: 'draft',
starts_with: 'blog',
is_startpage: 0,
per_page: 3
})
)
articles.value = data.value.data.stories
</script>
// AllArticles.vue (with cv and localization)
<script setup>
import { useI18n } from 'vue-i18n'
const { locale } = useI18n({
useScope: 'global'
})
defineProps({ blok: Object })
const articles = ref(null)
const storyblokApi = useStoryblokApi()
const { data } = await useAsyncData(
`blog-${new Date().getTime()}`,
async () => await storyblokApi.get('cdn/stories', {
version: 'draft',
starts_with: 'blog',
is_startpage: 0,
language: locale.value,
cv: new Date().getTime()
})
)
articles.value = data.value.data.stories
</script>
@papoms @codeflorist @Dawntraoz Have you run into this issue?
from storyblok-nuxt.
ad 1) if your are using useAsyncData
and payloads, server rendered and client data should be the same and not produce hydration errors. Are you re-fetching data on the client, or does the problem only happen, when in Storyblok's visual editor? If yes, the effect you describe could be due to this vue issue. A workaround would be to do all client side updates inside onMounted()
ad 2) I think you need to include the language in the useAsyncData
key e.g. like this:
useAsyncData(`blog-${locale.value}`,...
ad 3) Thats strange, since you are using different keys with useAsyncData
in your example.
As an alternative to useAsyncData
, you could utilize useState
like this:
// RecentArticles.vue
<script setup>
defineProps({ blok: Object })
const articles = useState('recent-articles')
const storyblokApi = useStoryblokApi()
if (!articles.value) {
const stories = await storyblokApi.get('cdn/stories', {
version: 'draft',
starts_with: 'blog',
is_startpage: 0,
per_page: 3
})
articles.value = stories
}
</script>
This doesn't seem to store it's data in the payload-files, but rather directly in the index.html
and inside a default.<hash>.js
, but imho that should be equivalent.
from storyblok-nuxt.
Hi @papoms & @codeflorist, thanks for opening and giving insights into this feature request.
I will talk about this internally with my manager, but in the meantime, will you be willing to participate in developing the composable if we have the green light?
@Dawntraoz I'll try to wrap up a pull request.
from storyblok-nuxt.
how is pagination solved for the examples above? or is it not resolved?
from storyblok-nuxt.
Thanks @bocooper-dev !
But how do you increment page.value, or were do you define it?
that's the part I am missing currently.
In my case I need all pages to resolve to a single promise. And then return the results.
(I have to fetch +500 stories and generate a single list with all of them without pagination)
At the moment i have to do some horrible looping in order to get all the pages for a certain section (like blog)
It looks more or less like this:
async function useStoryblokGetStoriesAsync(url, apiOptions) {
const storyblokApiInstance = useStoryblokApi()
let currentPage = 1
let results = []
const { data } = await useAsyncData(
`${cv}${url}${page.value}`,
async () => {
while (fetchingStories) {
const rs = await storyblokApiInstance.get('cdn/stories', {
...apiOptions,
version: 'draft',
cv: myGetCacheVersion(),
per_page: 10,
page: currentPage,
excluding_fields: apiOptions.excluding_fields || 'pageBody',
})
// ...some more things here
const currentPageStories = rs.data.stories || []
results = results.concat(currentPageStories)
currentPage++
}
return results
},
)
return data.value
}
This is the only way I've been able to loop through pages, but TBH I am not happy with it.
If you have a better, more concise idea, I am open to suggestions.
Thanks again!!!
from storyblok-nuxt.
this may also help https://www.storyblok.com/faq/how-to-load-more-than-100-stories-with-the-js-client
from storyblok-nuxt.
Impressive findings, you all, @nachoadjust, @bocooper-dev & @codeflorist, thanks a lot for this. You made my day! It's so cool to see you all collaborating and helping each other 🤩
Would you be up for a quick sync call? So we can include the solution in the SDK for everyone? Let me know 😍
from storyblok-nuxt.
Hi @Dawntraoz !
Thank you for the invitation!
I'd be happy to connect!
About the code:
Tho the code works for me I am not sure we can include the solution in the SDK yet.
I am encountering some problems (error handling mostly) that I don't know if they are related to the code here or to some other issue in my codebase.
from storyblok-nuxt.
Related Issues (20)
- Consider giving the option to use `~/components/storyblok` for Storyblok Components HOT 5
- Component could not be found for blok HOT 8
- What is the correct way to access a story content inside a Nuxt plugin? HOT 8
- `renderRichText()` not working HOT 2
- Does preventClicks in Storyblok bridge actually work? HOT 2
- Nuxt 3.4.0 - 3.8.2 + nitro 2.8.0 bug | [ERROR] No matching export in "node_modules/.pnpm/[email protected]/node_modules/unicorn-magic/default.js" for import "toPath" HOT 8
- Cannot read properties of null (reading 'parentNode') and Cannot read properties of null (reading 'subTree')
- cache not working anymore since v6.0.0 HOT 5
- Module breaks types for auto imported components HOT 16
- Enabling the @storyblok/nuxt module causes components to lose typings. HOT 7
- Internal link from rich text editor rendering wrong URL HOT 2
- Use nuxt preview composable to make sure that fetching is done properly
- Storyblok making requests clientside on full static site. HOT 16
- Cache version `cv=undefined` causes redirect HOT 1
- Add the option to set default API version (`draft` or `published`) from Nuxt Config and using an ENV variable HOT 4
- Add routes to " Hit rate limit..." messages. HOT 2
- ERROR Component could not be found for blok "ComponentName"! Is it defined in main.ts as "app.component("ComponentName", ComponentName); HOT 7
- Missing type for componetsDir HOT 2
- useAsyncStoryblok returns undefined when story is not found HOT 1
- Streamlining useAsyncStoryblok to nuxt's useAsyncData HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from storyblok-nuxt.