Loo Gie
Loo Gie

Reputation: 48

Handle browser back button with React router dom

this is my first time here

I am working on a website that shows infos about movies and tv shows using TMDB API, React, Redux and React Router Dom. I wanted to sort movies by genres and page. So in my Movies Page, i have a list of genres and each one of them has an ID which make my useEffect() hooks to rerender each time a new genre is clicked or the page is changed.

The link to the movies page looks like this movies/:genreID/:pageNumber. So basically, the idea was each time a genre is clicked or the page is changed, the url updates and i get the new genreID and pageNumber from it using useParams(), then i send them to dispatch and the component rerender.

My code looks like this

const Movies = ({ isFrench, isOpen }) => {

  const dispatch = useDispatch();
  const history = useHistory();
  const { genreID, pageNumber } = useParams();

  const language = isFrench ? "fr" : "";
  const [genres, setGenres] = useState(genreID);
  const [page, setPage] = useState(pageNumber);

  useEffect(() => {
    dispatch(fetchMovies(language, page, genres));
    history.push(`movies/${genres}/${page}`);
  }, [dispatch, language, page, genres, history]);

  const { popularMovies, numOfPages, isLoading } = useSelector(
    (state) => state.movies
  );

  //Change Category
  const changeCategoryHandler = (id) => {
    setPage(1);
    setGenres(id);
    getCategoryName(id);
  };

  //Print categories
  const frenchCategories = categoriesMoviesFR.map((category) => (
    <li onClick={() => changeCategoryHandler(category.id)} id={category.id}>
      {category.name}
    </li>
  ));
  
  ... 
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

The problem is that if i am on page 3 for example, and i press the browser's back button to return to page 2, I see that the link changes in the browser but the component is not updated. Same thing with the genres. If I quit Action for Adventure and hit the back button to go back to Action, I see the link changes but the component is not refreshed.

Has anyone ever encountered this kind of problem? Thank you for any help you can offer

Upvotes: 1

Views: 1320

Answers (2)

Janice Zhong
Janice Zhong

Reputation: 878

The problem is here:

  const { genreID, pageNumber } = useParams();
  const [genres, setGenres] = useState(genreID);
  const [page, setPage] = useState(pageNumber);

You are initialising your state with dynamic props value, but state's default value will never change, because useState is only called once. You can try printing out genreID and pageNumber, and genres & page to find out that.

Solution

You can directly use { genreID, pageNumber } throughout your Movies component. If you really need to store them in state, use useEffect like this:

useEffect(()=>{
  setGenres(genreID)
  setPage(pageNumber)
},[genreID, pageNumber])

I made a very simple demo for you to have a clear vision on this type of problem.

Upvotes: 1

Loo Gie
Loo Gie

Reputation: 48

So the index.js file looks like this

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { createStore, applyMiddleware, compose } from "redux";
import { Provider } from "react-redux";
import rootReducer from "./reducers";
import thunk from "redux-thunk";
import { BrowserRouter } from "react-router-dom";


const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(rootReducer, composeEnhancer(applyMiddleware(thunk)));

ReactDOM.render(
  <BrowserRouter>
    <React.StrictMode>
      <Provider store={store}>
        <App />
      </Provider>
    </React.StrictMode>
  </BrowserRouter>,
  document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Upvotes: 0

Related Questions