Code Monkey home page Code Monkey logo

Comments (14)

bocooper-dev avatar bocooper-dev commented on June 2, 2024 1

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.

codeflorist avatar codeflorist commented on June 2, 2024 1

@nachoadjust

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.

nachoadjust avatar nachoadjust commented on June 2, 2024 1

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.

papoms avatar papoms commented on June 2, 2024

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.

codeflorist avatar codeflorist commented on June 2, 2024

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.

Dawntraoz avatar Dawntraoz commented on June 2, 2024

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.

bocooper-dev avatar bocooper-dev commented on June 2, 2024

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.

@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:

  1. The page shows hydration errors on page refresh. You can even see the blog cards double in quantity with ugly broken CSS.
  2. 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.
  3. 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.

codeflorist avatar codeflorist commented on June 2, 2024

@bocooper-dev

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.

codeflorist avatar codeflorist commented on June 2, 2024

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.

nachoadjust avatar nachoadjust commented on June 2, 2024

how is pagination solved for the examples above? or is it not resolved?

from storyblok-nuxt.

nachoadjust avatar nachoadjust commented on June 2, 2024

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.

bocooper-dev avatar bocooper-dev commented on June 2, 2024

@nachoadjust

this may also help https://www.storyblok.com/faq/how-to-load-more-than-100-stories-with-the-js-client

from storyblok-nuxt.

Dawntraoz avatar Dawntraoz commented on June 2, 2024

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.

nachoadjust avatar nachoadjust commented on June 2, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.