'REACT - Express : fetching data doesn't work on reload when user connected

I've deploy my first app using React with Nodejs/Express/MongoDB but I'm running through a bug I couldn't find any solution, so I'm coming here to find some help.

This is the app : https://movie-app-marielyse.herokuapp.com/

As soon as the user connects, he can access the data, but if the page is reloaded, the fetch is not working anymore.

Here is the code where the fetch happens :

import './App.css';
import "./index.css"
import React, {useState, useEffect, useRef} from 'react'
import {BrowserRouter as Router, Routes, Route} from 'react-router-dom'
import Register from './components/Register';
import Login from './components/Login'
import Home from './pages/Home';
import Auth from './pages/Auth';
import Movie from './pages/Movie'
import NotFound from './pages/Notfound';
import FavoritesMovies from './pages/Favorites';
import UserContextProvider from './contexts/UserContext';
import RequireAuth from './contexts/RequireAuth';

function App() {

  const defaultUser = {name:"Stranger", email: "[email protected]"}

  const [moviesList, setMoviesList] = useState([])
  const [initialML, setInitialML] = useState([])
  const [userInfo, setUserInfo] = useState(defaultUser)
  // console.log(userInfo.name)
 
useEffect( () => {getMovies()}, [])

  function getMovies() {
    fetch('/movies')
    .then(response => response.json())
    .then(data => {
      const movies= data.movies
      setMoviesList(movies) 
      setInitialML(movies) 
    })
    .catch(err => console.log(err))
  
}

  return (
    <div className="App">
        <UserContextProvider user={{userInfo, setUserInfo}}>
          <Router>
            <main>
              <Routes>
                <Route path="/" element={<Home moviesList={moviesList} setMoviesList={setMoviesList} initialMovieList={initialML}/>}/>
                <Route path="/auth/*" element={<Auth />} >
                    <Route path="login" element={<Login/>} />
                    <Route path="register" element={<Register/>} />
                    <Route path="logout" element={<Register/>} />
                    {/* <Route path="*" element={<NotFound />}/> */}
                </Route>
                <Route path="movies/:movieId" element={<Movie moviesList={moviesList} setMoviesList={setMoviesList}  />} />
                <Route path="favorites" element={
                      <RequireAuth> 
                        <FavoritesMovies />
                      </RequireAuth>} />
                <Route path="*" element={<NotFound />}/>
              </Routes>
            </main>
          </Router>
          </UserContextProvider> 
     

    </div>
  );
}

export default App;


Solution 1:[1]

In general your code can be modified like this, roughy:

  • remove fetch /movies from App and place it inside Home - this would make sure useEffect/fetch triggers when / route is hit. And is good practice to keep things separated and well organized.

App component

function App() {

  const defaultUser = {name:"Stranger", email: "[email protected]"}
  const [userInfo, setUserInfo] = useState(defaultUser)

  return (
    <div className="App">
        <UserContextProvider user={{userInfo, setUserInfo}}>
          <Router>
            <main>
              <Routes>
                <Route exact path="/" element={<Home />}/>
                <Route path="/auth/*" element={<Auth />} >
                    <Route path="login" element={<Login/>} />
                    <Route path="register" element={<Register/>} />
                    <Route path="logout" element={<Register/>} />
                    {/* <Route path="*" element={<NotFound />}/> */}
                </Route>
                <Route path="movies/:movieId" element={<Movie moviesList={moviesList} setMoviesList={setMoviesList}  />} />
                <Route path="favorites" element={
                      <RequireAuth> 
                        <FavoritesMovies />
                      </RequireAuth>} />
                <Route path="*" element={<NotFound />}/>
              </Routes>
            </main>
          </Router>
          </UserContextProvider> 
    </div>
  );
}

export default App;

Home component

function Home() {
  const [moviesList, setMoviesList] = useState([])
  const [initialML, setInitialML] = useState([])
 
  useEffect( () => {getMovies()}, []);

  function getMovies() {
    fetch('/movies')
    .then(response => response.json())
    .then(data => {
      const movies= data.movies
      setMoviesList(movies) 
      setInitialML(movies) 
    })
    .catch(err => console.log(err))
  }

  return (....)
}

And i am not sure which version you are using but if it is not v6, more on React.Router could be checked- https://v5.reactrouter.com/web/api/Switch and exact https://dev.to/danhjoo7/using-a-switch-component-in-react-router-d2k

Solution 2:[2]

<Route path="/" element={<Home moviesList={moviesList} setMoviesList={setMoviesList} initialMovieList={initialML}/>}/>

On this line or where ever there is moviesList and initialML try doing:

<Route path="/" element={<Home moviesList={moviesList && moviesList} setMoviesList={setMoviesList} initialMovieList={initialML && initialML}/>}/>

Your fetch request is async so it takes some time but the compenent is already rendered before that thats probably it looks data is not being fetched.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 RBT