Home > Software engineering >  One of my routes tries to render a different component
One of my routes tries to render a different component

Time:10-05

ROUTES

          <Routes>
            <Route
              exact
              path="/"
              element={
                <div>
                  <BlogForm />
                  <BlogList />
                </div>
              }
            />
            <Route path="/blogs" element={<UserList />} />
            <Route path="/users" element={<UserList />} />
            <Route path="/users/:id" element={<User />} />
            <Route path="/blogs/:id" element={<BlogSingle />} />
          </Routes>

Here I have all my routes. All of them works except the last one '/blogs/:id' which renders <BlogSingle />. It throws an uncaught type error from my <Blog/> component which is rendered inside <BlogList />. I have my <Link> components in <Blog/> but I don't think that's the cause of the problem since I tried deleting it and going to /blogs/:id manually. Why does my last Route re-renders the <Blog/> component. Any thoughts?

BLOGLIST

import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { initializeBlogs } from '../reducers/blogReducer'
import Blog from './Blog'

const BlogList = () => {
  const dispatch = useDispatch()

  const user = useSelector(({ login }) => {
    return login
  })

  useEffect(() => {
    dispatch(initializeBlogs())
  }, [dispatch])
  const blogs = useSelector(({ blog }) => {
    return blog
  })

  return (
    <div>
      {blogs.map((blog) => (
        <Blog key={blog.id} user={user} blog={blog}></Blog>
      ))}
    </div>
  )
}

export default BlogList

BLOG

[import { useState } from 'react'
import { useDispatch } from 'react-redux'
import { saveLikes, deleteBlog } from '../reducers/blogReducer'
import { Link } from 'react-router-dom'

const Blog = ({ user, blog }) => {
  const \[visualForm, setVisualForm\] = useState(true)
  const dispatch = useDispatch()

  const longFormVisible = { display: visualForm ? 'none' : '' }
  const shortFormVisible = { display: visualForm ? '' : 'none' }

  const toggleForm = () => {
    setVisualForm(!visualForm)
  }

  const showDelete = blog.user.id.toString() === user\[0\].id.toString()

  const blogStyle = {
    paddingTop: 10,
    paddingLeft: 2,
    border: 'solid',
    borderWidth: 1,
    marginBottom: 5,
  }

  return (
    <div>
      <div style={Object.assign({}, blogStyle, longFormVisible)}>
        {blog.title} {blog.author}
        <button type="submit" onClick={toggleForm}>
          hide
        </button>
        <br />
        {blog.url}
        <br />
        likes: {blog.likes}{' '}
        <button type="submit" onClick={() => dispatch(saveLikes(blog))}>
          like
        </button>
        <br />
        {blog.user.name}
        <br />
        {showDelete ? (
          <button type="submit" onClick={() => dispatch(deleteBlog(blog))}>
            delete
          </button>
        ) : (
          ''
        )}
      </div>
      <div style={Object.assign({}, blogStyle, shortFormVisible)}>
        <Link to={`blogs/${blog.id}`}>
          {blog.title} {blog.author}
        </Link>
        <button type="submit" onClick={toggleForm}>
          view
        </button>
      </div>
    </div>
  )
}

export default Blog][1]

BLOGSINGLE

import { useMatch } from 'react-router-dom'
import { useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { initializeUsers } from '../reducers/userReducer'
import { initializeBlogs } from '../reducers/blogReducer'

const BlogSingle = () => {
  const dispatch = useDispatch()

  useEffect(() => {
    dispatch(initializeUsers())
  }, [dispatch])

  useEffect(() => {
    dispatch(initializeBlogs())
  }, [dispatch])

  /*const users = useSelector(({ user }) => {
    return user
  })*/

  const blogs = useSelector(({ blog }) => {
    return blog
  })

  const match = useMatch('/blogs/:id')

  const blog = match
    ? blogs.find((blog) => blog.id === match.params.id.toString())
    : null
  console.log(match.params.id.toString())

  if (!blog) {
    return null
  }
  return (
    <div>
      <h1>
        {blog.title} {blog.author}
      </h1>
      <h2>added blogs</h2>
    </div>
  )
}

export default BlogSingle

Route below also works. I used <UserList /> just to try. I actually don't have a view for /blogs url. Only 'blogs/:id'.

 <Route path="/blogs" element={<UserList />} />

I added the error in the link.

/localhost:xxxx/blogs/62965dbc5553186f396413ac when I go to this URL I get this error. ERROR

Uncaught TypeError: Cannot read properties of undefined (reading 'user') at Blog (bundle.js:142:27) at renderWithHooks (bundle.js:36135:22) at mountIndeterminateComponent (bundle.js:40752:17) at beginWork (bundle.js:42207:20) at HTMLUnknownElement.callCallback (bundle.js:24059:18) at Object.invokeGuardedCallbackDev (bundle.js:24108:20) at invokeGuardedCallback (bundle.js:24170:35) at beginWork$1 (bundle.js:47132:11) at performUnitOfWork (bundle.js:46269:16) at workLoopSync (bundle.js:46182:9)

Thanks in advance.

CodePudding user response:

The router code you've pasted has

<Route path="/blogs" element={<UserList />} />
<Route path="/users" element={<UserList />} />

Presumably, the first element should be <BlogList /> – that should prevent it from trying to render a different component.'

Additionally, the order of routes within <Routes> matters:

<Route path="/users/:id" element={<User />} />
<Route path="/blogs/:id" element={<BlogSingle />} />
<Route path="/blogs" element={<BlogList />} />
<Route path="/users" element={<UserList />} />

should do the trick.

CodePudding user response:

I'm just an idiot. I accidentally imported BlogSingle as 'import BlogSingle from './Blog'' instead of './BlogSingle'. It is now working.

  • Related