Amrou rabti
Amrou rabti

Reputation: 149

How to redirect to not found page if slug doesn't exist using React Router Dom?

Let's say I have these routes:

<Switch>
  <Route exact path="/myflix/:slug" component={Home} />
  <Route exact path="/myflix/:slug/register" component={Signup} />
  <Route exact path="/myflix/:slug/event" component={Event} />
  <Route exact path="/myflix/:slug/contact" component={Contact} />
  <Route exact path="/myflix/:slug/login" component={Login} />
  <Route exact path="/myflix/:slug/show-details" component={ShowList} />
  <Route exact path="/myflix/:slug/*" component={NotFound} />
  <Route path="*" exact={true} component={NotFound} />
  <Redirect to="/not-found" />

  {/* <Route path="*" element={<NotFound />} /> */}
</Switch>

We have certain slugs from an API, in this form:

[
  {
    id: 1,
    title: "_flix",
    slug: "_flix",
    status: true,
    viewTime: null,
    langue: null,
    createdAt: "2021-06-24",
    updatedAt: null,
  },
  {
    id: 9,
    title: "test_flix",
    slug: "test_flix",
    status: true,
    viewTime: null,
    langue: null,
    createdAt: "2021-06-24",
    updatedAt: null,
  },
  {
    id: 10,
    title: "flix_2",
    slug: "flix_2",
    status: true,
    viewTime: null,
    langue: null,
    createdAt: "2021-06-24",
    updatedAt: null,
  },
]

When I make an invalid slug, I want to redirect to the NotFound page:

useEffect(() => {
  getSlug(slug)
    .then((res) => {
      const { id } = res.data;
      document.title = res.data.title;
      getSetting(id).then((result) => {
        setStyle(result.data);
        getLangue(id).then((res) => {
          setlang(res.data.langue);
        });
      });
    })
    .catch((error) => (window.location.href = "/not-found"));
}, [slug]);

I used the above code (see the .catch), but when I make an invalid slug, it redirects not found page and refreshes the page. I need to redirect without refreshing. Any solution?

Upvotes: 3

Views: 2211

Answers (2)

Youssouf Oumar
Youssouf Oumar

Reputation: 45963

window.location.href refreshes the page. Since you seem to be using React Router Dom v5, you should be using useHistory to make redirections. Here is an overview of how you would use it (notice the comments):

import { useHistory } from "react-router-dom";

function HomeButton() {
  let history = useHistory(); // you call it at the top level of the component

  function handleClick() {
    history.push("/home"); // use it wherever you want
  }

  return (
    <button type="button" onClick={handleClick}>
      Go home
    </button>
  );
}

Not related to useHistory or the redirection, but you could optimize slightly your routes setup:

<Switch>
  <Route exact path="/myflix/:slug" component={Home} />
  <Route exact path="/myflix/:slug/register" component={Signup} />
  <Route exact path="/myflix/:slug/event" component={Event} />
  <Route exact path="/myflix/:slug/contact" component={Contact} />
  <Route exact path="/myflix/:slug/login" component={Login} />
  <Route exact path="/myflix/:slug/show-details" component={ShowList} />
  <Route exact path="/not-found" component={NotFound} />
  <Redirect to="/not-found" />
</Switch>

For React Router Dom v6, use useNavigate is to be used instead of useHistory.

Upvotes: 2

Drew Reese
Drew Reese

Reputation: 202874

Issue

Using window.location.href = "/not-found" mutates the current location and reloads the page, i.e. it will remount the entire React app. Use an imperative redirect to the "/not-found" route.

Solution

import { useHistory } from 'react-router-dom';

...

const history = useHistory();

...

useEffect(() => {
  getSlug(slug)
    .then((res) => {
      const { id, title } = res.data;
      document.title = title;
      getSetting(id)
        .then((result) => {
          setStyle(result.data);
        });
      getLangue(id)
        .then((res) => {
          setLang(res.data.langue);
        });
    })
    .catch((error) => {
      history.replace("/not-found"); // REPLACE = redirect
    });
}, [slug]);

Render a Route on path="/not-found" that can be redirected to.

<Switch>
  <Route path="/myflix/:slug/register" component={Signup} />
  <Route path="/myflix/:slug/event" component={Event} />
  <Route path="/myflix/:slug/contact" component={Contact} />
  <Route path="/myflix/:slug/login" component={Login} />
  <Route path="/myflix/:slug/show-details" component={ShowList} />
  <Redirect from="/myflix/:slug/*" to="/not-found" /> // <-- redirect unhandled paths
  <Route path="/myflix/:slug" component={Home} />
  <Route path="/not-found" component={NotFound} /> // <-- render NotFound component route
  <Redirect to="/not-found" />
</Switch>

Upvotes: 0

Related Questions