I am having some issues with the way I currently have the flow set up. I have a component ArticeList
that is listening to articles and when clicking on it it will redirect you to the individual article page. I am using next/Link
to redirect the article to its landing page and passing the id as a hidden query using the Link attribute as
for example:
<Link href={`/article/${ConvertTitleToURL(data.name)}/?id=${data.id}`} as={`/article/${ConvertTitleToURL(data.name)}`}>
I am then using next/router
on my [...article].js
page to get the hidden id and use it fetch the article content. For example:
const router = useRouter()
const articleId = router.query.id
const apiURL = 'https://test.api/' id
const { data, error } = useSWR(`${apiURL}`, fetcher)
I am able to successfully make this call with the way it's currently set up but my issue is if the user refreshes the page the id that was originally passed from Link
is now loss and I get an error because articleId
equals nothing.
Is it possible to save the article id on the first load so if a user refreshes the page the content will still load?
I've attempted to solve this issue by using a react hook but I am still receiving the same error. How can I work around this?
Here is my code sample:
ArticleList component which links passing the id
import Link from 'next/link'
function ConvertCodeTitleToURL(title) {
let url = ""
if (title) {
url = title.replace(".","").toLowerCase()
url = url.replace(/,/g, "")
url = url.replace("(", "") // added for (except) cases
url = url.replace(/\s/g, "-")
} else {
url = "/"
}
return url
}
const ArticleList = ({articles}) => {
return (
<div className="container-1200">
{articles && articles.map(data => (
<div key={data.id}>
{data.results.length > 0 &&
<div key={data.id}>
<div className="d-flex justify-space-between">
<div className="heading-30 letter-spacing-25 text-dark-blue m-l-n-20">{data.name}</div>
<Link href={`/articles/${ConvertCodeTitleToURL(data.name)}/?id=${data.id}`} as={`/articles/${ConvertCodeTitleToURL(data.name)}`}>
</Link>
</div>
</div>
}
</div>
))}
</div>
)
}
export default ArticleList
article page which is using the id passed from Link
to fetch data
import React, { useState } from 'react';
import useSWR from 'swr'
import { useRouter } from 'next/router';
import ArticleLayout from '../../components/ArticleLayout';
const fetcher = (...args) => fetch(...args).then(res => res.json())
function Articles() {
const router = useRouter()
const articleId = router.query.id
const [id, setId] = useState(articleId);
const apiURL = 'https://test.api/' id
const { data, error } = useSWR(`${apiURL}`, fetcher)
if (error) return <div>failed to load ...</div>
if (!data) return <div>loading....</div>
return (
<>
<ArticleLayout article={data}/>
</>
)
}
export default Articles
CodePudding user response:
Save / load id from localStorage. Note that it doesn't handle edge cases.
import React, { useState } from 'react';
import useSWR from 'swr'
import { useRouter } from 'next/router';
import ArticleLayout from '../../components/ArticleLayout';
const ISSERVER = typeof window === "undefined";
const fetcher = (...args) => fetch(...args).then(res => res.json())
function Articles() {
const router = useRouter()
const [id, setId] = useState(() => {
const articleId = router.query.id
if (ISSERVER) return articleId;
if (articleId) {
localStorage.set("articleId", articleId);
return articleId;
} else {
return localStorage.get("articleId");
}
});
const apiURL = 'https://test.api/' id
const { data, error } = useSWR(`${apiURL}`, fetcher)
if (error) return <div>failed to load ...</div>
if (!data) return <div>loading....</div>
return (
<>
<ArticleLayout article={data}/>
</>
)
}
export default Articles
CodePudding user response:
useRouter take time to load when you reload page. you can do conditinal fetching on useSWR hook
const router = useRouter()
const articleId = router?.query?.id || '' //check if id exist
const apiURL = 'https://test.api/' id
//conditional fetching, null means fetch nothing if articleId not true
const { data, error } = useSWR(articleId ?`${apiURL}`:null, fetcher)