Going from dynamic route to dynamic route won't update component/page

Viewed 15

As the title says: when I am currently on a dynamic route <Route path=':username' element={ <UserPage /> } /> and try to, for example, go from http://localhost:3000/Fexell to http://localhost:3000/Test, the page won't update. How do I make the component/page refresh to load from the new route? Thanks

App.js:

import { useState, useEffect } from 'react'
import { BrowserRouter as Router, Routes, Route, Navigate, Outlet } from 'react-router-dom'
import axios from 'axios'

import HomePage from './pages/home/home.page'
import LoginPage from './pages/login/login.page'
import SignupPage from './pages/signup/signup.page'
import SettingsPage from './pages/settings/settings.page'
import UserPage from './pages/user/user.page'
import MePage from './pages/me/me.page'
import PostPage from './pages/post/post.page'

import HeaderComponent from './components/header/header.component'
import SidebarLeftComponent from './components/sidebars/sidebar-left.component'
import SidebarRightComponent from './components/sidebars/sidebar-right.component'
import ContentComponent from './components/content/content.component'

import { UserContext } from './context/user.context'
import { PostsContext } from './context/posts.context'
import { SocketContext, Socket } from './context/socket.context'

import './App.sass'

const ProtectedRoutes = ({ user, redirectPath = '/login' }) => {
  if(!user) return <Navigate to={ redirectPath } />

  return <Outlet />
}

const App = () => {
  const [ user, setUser ] = useState(JSON.parse(window.localStorage.getItem('user')))
  const [ posts, setPosts ] = useState()

  const loadAllPosts = async () => {
    if(user) {
      await axios({
        method: 'GET',
        url: process.env.REACT_APP_API_URL + '/posts/',
        headers: {
          Authorization: `jwt ${ user.token }`
        }
      })
        .then((response) => {
          setPosts(response.data)
        })
        .catch((error) => console.error(error))
    }
  }
  
  useEffect(() => {
    
    window.addEventListener('beforeunload', () => {
      Socket.close()
    })
    
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  return (
    <UserContext.Provider value={[ user, setUser ]}>
      <SocketContext.Provider value={ Socket }>
          <PostsContext.Provider value={[ posts, setPosts ]}>
            <div id='App' className='app'>
              <div className='app-container'>
                <Router>
                  { user && (
                    <>
                      <HeaderComponent loadAllPosts={ loadAllPosts } />
                      <SidebarLeftComponent />
                      <SidebarRightComponent />
                    </>
                  ) }
                  <Routes>
                    <Route exact path='/' element={ <ContentComponent /> }>

                      <Route path='login' element={ user ? <Navigate to='/' /> : <LoginPage /> } />
                      <Route path='signup' element={ user ? <Navigate to='/' /> : <SignupPage /> } />

                      <Route element={ <ProtectedRoutes user={ user } /> }>
                        <Route index element={ <HomePage loadAllPosts={ loadAllPosts } /> } />
                        <Route path='settings' element={ <SettingsPage /> } />
                        <Route path='me' element={ <MePage /> } />
                        <Route path=':username' element={ <UserPage /> } />
                        <Route path='post/:id' element={ <PostPage loadAllPosts={ loadAllPosts } /> } />
                      </Route>
                    </Route>
                  </Routes>
                </Router>
              </div>
            </div>
          </PostsContext.Provider>
      </SocketContext.Provider>
    </UserContext.Provider>
  );
}

export default App

user.page.jsx:

import { useState, useEffect, useContext } from 'react'
import { useParams } from 'react-router-dom'
import axios from 'axios'

import PostFormComponent from '../../components/posts/post-form.component'
import PageTitleComponent from '../../components/ui/page-title.component'
import UserPostsComponent from '../../components/posts/user-posts.component'

import { UserContext } from '../../context/user.context'
import { LoadingContext } from '../../context/loading.context'

import './user.styles.sass'

const UserPage = () => {
  const [ user, ] = useContext(UserContext)

  const [ userFromId, setUserFromId ] = useState()
  const [ isLoading, setLoading ] = useState(true)
  const { username } = useParams()

  const getUser = async () => {
    await axios({
      method: 'GET',
      url: process.env.REACT_APP_API_URL + `/users/${ username }`,
      headers: {
        Authorization: `jwt ${ user.token }`
      }
    })
      .then((response) => {
        setUserFromId(response.data)
        setLoading(false)
      })
      .catch((error) => console.error(error))
  }

  useEffect(() => {

    getUser()

    console.log('Page initial render')

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  return (
    <LoadingContext.Provider value={[ isLoading, setLoading ]}>
      <div id='User' className='page user'>
        <div className='container'>
          <PageTitleComponent text={ `${ userFromId?.firstname } "${ userFromId?.username }" ${ userFromId?.surname }` } />
          { userFromId && user.user._id === userFromId._id && (
            <PostFormComponent placeholder={ `Vad gör du just nu, ${ user.user.firstname }?` } />
          ) }
          { userFromId && user.user._id !== userFromId._id && (
            <PostFormComponent toUser={ userFromId } placeholder={ `Skriv något till ${ userFromId?.firstname }...` } />
          ) }
          { userFromId && (
            <UserPostsComponent id={ userFromId._id } />
          ) }
        </div>
      </div>
    </LoadingContext.Provider>
  )
}

export default UserPage

Thanks

1 Answers

You want to reload the data when you get to a different route. To do this you should change the dependency array of your useEffect to include username. Your useEffect should look like this:

  useEffect(() => {

    getUser()

    console.log('Page initial render')

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [username])

Explanation

This change will tell useEffect to run again whenever username changes. When you navigate to a different page, the username param will change, so useEffect will run again, calling getUser() to get the new data.

Related