fetching data in React with DynamicRoutes, nextJS and useEffect

Viewed 3118

I have a blog link. Link is dynamic route with blog id. It's the Link wrapper from Next.

//link
<h3 className="blogTitle">
    <Link href="[blog]" as={props.item.postingId}>{props.item.title}</Link>
</h3>

Now I want to pass "blog id" to the component and to present data in a new page.

//page where link leads to
const ad = () => {
    const router = useRouter()
    const {
        query: {blog},
    } = router
    
    const [data, setData] = useState(false);
    const [loading, setLoading] = useState(false);   
                   
    console.log('....outside useEffect log', blog)
    useEffect(() => {
        console.log('useEffect consolelog', blog); 
        axios.get('httpwww.blogapiadress.com/'+ ad)
            .then(response => setData(response.data))
            .then(setLoading(false))
    }, [])
  
    return( 
        <Container fluid className="padding0">
            /// data should be here.
        </Container>
    );
}
    
export default ad;

Problem: in useEffect console.log('blog', blog) returns undefined, so router does not return value from query. However, outside of useEffect it does. How to solve that issue, I want to fetch data related to the router query?

Since axios is getting undefined instead of blog id, I am getting 404.

enter image description here

4 Answers

Looking for answer for a few hours, and when I posted question on stack.. I figured out the answer.

So problem was that query is empty with next static generation at build time https://nextjs.org/docs/api-reference/next/router#router-object

I havent found best solution, but i found working one. I got blog id from the windows.location href

  useEffect(()=>{
    const last = window.location.href.split('/').pop();
    console.log('last', last)
    axios.get('https://blogpostings.com/'+last)
        .then(response => setData(response.data))
      }, [])

I am not sure if its proper or good way, but it works. I hope someone will find this helpful.

I don't think you need to use the global window object to access dynamic data related to your route -- you should be able to use the Next router. I think the way you are defining href -- the only required prop for Link is causing issues. Looking at docs and your current exampel you probably want to use something like:

        <Link
          href={{
            pathname: '/[blog]',
            query: { blog: props.item.postingId },
          }}
        >
           <a>{props.item.title}</a>
        </Link>

     // or

     <Link href={`/${encodeURIComponent(props.item.postingId)}`}>
        <a>{props.item.title}</a>
    </Link>

Then you should be able to properly access [blog] (i.e., your postingId) using Router. For example, if your route was defined dynamically by /[blog].js, you could use the following:

     import { useRouter } from 'next/router'

     const ad = () => {
        const router = useRouter()
        const { blog } = router.query

        const [data, setData] = useState(false);
        const [loading, setLoading] = useState(false);
               
        useEffect(()=>{
             axios.get('httpwww.blogapiadress.com/'+ blog)
                 .then(response => { 
                    setData(response.data)
                    setLoading(false)
              })
         }, [])


    if (loading || !data) return <div> Loading... </div>

    return( 
       <Container fluid className="padding0">
         /// Render data
      </Container>
    );
}

export default ad;

You can use getStaticProps() to fetch the blog data at build time.

Example:

// posts will be populated at build time by getStaticProps()
function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

// This function gets called at build time on server-side.
// It won't be called on client-side, so you can even do
// direct database queries. See the "Technical details" section.
export async function getStaticProps() {
  // Call an external API endpoint to get posts.
  
  // Access route params:
  const blog = context.query.blog // or context.params.blog for parametrized routes
  return {

  const res = await fetch('https://...')
  const posts = await res.json()

  // By returning { props: { posts } }, the Blog component
  // will receive `posts` as a prop at build time
  return {
    props: {
      posts,
    },
  }
}

export default Blog

More info on NextJS docs.

If you want get the query parameter from the link, you need to insert at the end of the url: https://sample-link.com?blog=123

Then same as your code above:

import { useRouter } from 'next/router'

const router = useRouter()

const {
   query: {blog}
} = router;

console.log("blog: ", blog)

Result:

blog: 123
Related