I'm trying to implement SSR in my project, but constantly getting this 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?
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>