0

I'm trying to implement SSR in my project, but constantly getting this error/warn.

error/warn

How can I know what is wrong with my code?

I have a lot of components in my project, dont know if I need to show you all of my code, but there is main TypeScript

import {Book} from '@/data/data'

const useBooksStore = () => {


    const books = useState<Book[]>('books', () => [])
    const savedBooks = useState<String[]>('savedBooks', () => [])
    const isLoading = useState('isLoading', () => false)
    const apiKey = 'AIzaSyBz-gCuGyQopm_Ey2QWPrMGghy0D0e1FYY'

    const booksCookie = useCookie('savedBooks')


    //loading the list of books on query
    async function loadBooks(query: string) {

        const response = await fetch(`https://www.googleapis.com/books/v1/volumes?q=${query}&key=${apiKey}`)

        if (response.ok) {
            const result = await response.json()
            if (result.items) {

                books.value = books.value.filter(book => book.favourites === true)
                result.items.forEach(item => {
                    const existingBook = books.value.find(book => book.id === item.id)
                    if (!existingBook) {
                        let data = constructBookData(item)
                        books.value.unshift(data)
                    }
                })
            } else {
                books.value = books.value.filter(book => book.favourites === true)

                throw new Error('Not Found')
            }

        }
    }

    //loading saved books from cookies
    async function loadSavedBooks() {
        if (booksCookie.value) {
            savedBooks.value = booksCookie.value
        }
        let response, result
        for (const savedBook of savedBooks.value) {
            const existingBook = books.value.find(book => book.id === savedBook)
            if (!existingBook) {
                response = await fetch(`https://www.googleapis.com/books/v1/volumes/${savedBook}?key=${apiKey}`)
                if (response.ok) {
                    result = await response.json()
                    if (!books.value.find(book => book.id === result.id)) {
                        let data = constructBookData(result)
                        data.favourites = true
                        books.value.push(data)
                    }
                }
            } else {
                existingBook.favourites = true
            }
        }

    }

    //returns a new book object
    function constructBookData(result): Book {
        const data = {
            id: result.id,
            title: String(result.volumeInfo.title),
            imgUrl: result.volumeInfo.imageLinks && result.volumeInfo.imageLinks.thumbnail,
            shortDescr: result.volumeInfo.description,
            price: result.saleInfo.saleability === "FOR_SALE" ? Math.floor(result.saleInfo.retailPrice.amount) : result.saleInfo.saleability.split('_').join(' '),
            infoLink: result.volumeInfo.infoLink,
            favourites: false
        }
        return data

    }

    //handling loading (needed for loading spinner to show)
    async function handleLoading(callback) {
        isLoading.value = true
        try {
            await callback()
        } catch (err) {
            throw err
        } finally {
            isLoading.value = false
        }

    }

    //toggle favourite status of a book card
    function toggleFavourite(bookId: string) {
        const book = books.value.find(book => book.id === bookId)
        book.favourites = !book.favourites
        if (book.favourites && !savedBooks.value.find(book => book === bookId)) {
            savedBooks.value.push(book.id)
        } else {
            savedBooks.value.splice(savedBooks.value.findIndex(book => book === bookId), 1)
        }
        booksCookie.value = JSON.stringify(savedBooks.value)
    }

    //returns a list of saved books
    function getSavedBooks() {
        if (books.value) {
            return books.value.filter(book => book.favourites === true)
        }
    }

    //returns loading status
    function getLoading() {
        return isLoading.value
    }

    return {
        books,
        loadBooks,
        getSavedBooks,
        toggleFavourite,
        loadSavedBooks,
        handleLoading,
        getLoading
    }

}
export default useBooksStore

My main question is how can I know whats wrong with my code to solve this problem?

kissu
  • 40,416
  • 14
  • 65
  • 133
  • Hi, you're using Nuxt2 or 3 here? Did you looked at that one? https://stackoverflow.com/a/67978474/8816585 There is a difference between your server and client side code, or maybe some invalid HTML. So, make a comparison with your website with JS disabled and enabled to find out where this may come from. Also, commenting part of your code to spot the issue may be quite helpful IMO. – kissu Aug 06 '22 at 18:08
  • I'm using Nuxt 3 and Tailwind. With disabled javascript in browser content donesn't show at all. But there in no warn eather) – Dmytro Afanasiev Aug 06 '22 at 18:21
  • i didn't find that particular error on the interner, so i wonder how can i fix it? – Dmytro Afanasiev Aug 06 '22 at 18:23
  • So don't use SSR for that part? Start commenting parts of your code I guess. – kissu Aug 06 '22 at 18:43

1 Answers1

0

I found an answer. The issue was in this code

<component :is="type === 'link' ? 'a' :
    (type === 'button' && 'button')" :href='href' class="btn" @click="emit('click')" :class="class">
     <slot/>
   </component>

So I think dont use this type of component rendering, because it is not SSR friendly a guess) I rewrite it to this code

 <a v-if="type === 'link'" :href="href" class="btn" @click="emit('click')">
     <slot/>
   </a>
   <button v-else-if="type === 'button'" :href="href" class="btn" @click="emit('click')">
     <slot/>
   </button>
kissu
  • 40,416
  • 14
  • 65
  • 133