10

I have a [slug].js page that will fetch API to get the destination page

export async function getServerSideProps({ query, res }) {
    const slug = query.slug;
    try {
        const destination = await RoutingAPI.matchSlug(slug);
        res.writeHead(302, { Location: destination });
        res.end();
        // return {
        //     redirect: {
        //         permanent: true,
        //         destination,
        //     },
        // }
    } catch (error) {
        return {
            notFound: true
        }
    }
}

If I client redirect from another page to slug page, it works and keeps URL the same as slug but it makes the browser reload. If I use

return {
     redirect: {
        permanent: true,
        destination,
     },
}

it will not reload the browser but it change URL to the destination, not the same as slug. How do i fix this problem? I would appreciate any ideas, thanks

iamhuynq
  • 5,357
  • 1
  • 13
  • 36
  • 2
    Could you set up a repo to reproduce the issue? and if you can also provide the sequence of URLs you are getting vs. the one you are expecting would be nice too – diedu Mar 06 '21 at 18:13
  • @diedu you can check in here https://codesandbox.io/s/thirsty-sound-5wvy8, i want the destination page keep the url as 'something-slug', not 'destination' – iamhuynq Mar 07 '21 at 02:15
  • How are you doing the redirection on the client-side? the one you mentioned works – diedu Mar 07 '21 at 05:09
  • I use `res.writeHead(302,...`, it keep url as slug but it makes browser reload. But i dont know why it can not show on codesandbox – iamhuynq Mar 07 '21 at 05:19
  • 1
    I don't see a way to achieve this with current customization options, you could take a look at the custom server or rewrites feature but I recommend you to open a discussion on github to add `as` option in the redirect that is returned from `getServerSideProps`. God knows how long it'd take to go live though :/ – diedu Mar 08 '21 at 16:33
  • 2
    @iamhuynq What is your goal exactly? You want to show different component (page) and have different `getServerSideProps` for some of your "destinations", but keep url? – Danila Mar 09 '21 at 21:18
  • ok.. why don't you have client side script that will just re-write to the tab? as in you can have the same button, but on `click` event, prevent the default(`event.preventDefault()`), let `someVar` be the `await fetch` the button's href `event.path[0].href`, and send re-write to the document the response(`await someVar.text()`)? – The Bomb Squad Mar 12 '21 at 15:13
  • @iamhuynq Can you please clarify what happens in `RoutingAPI.matchSlug(slug)`? Adding that code would be helpful. Also, does anything else needs to happen in `getServerSideProps` or is it just serving as a redirect? – juliomalves Mar 12 '21 at 18:20
  • @iamhuynq check my answer when you're ready ;D – The Bomb Squad Mar 12 '21 at 18:50

2 Answers2

0

You can use rewrites to achieve this. From the docs:

Rewrites allow you to map an incoming request path to a different destination path.

In your next.config.js add this:

module.exports = {
  async rewrites() {
    return [
      {
        source: "/:slug",
        destination: "/your-destination",
      },
    ];
  },
};

rewrites is an async function that expects an array to be returned holding objects with source and destination properties:

  • source is the incoming request path pattern.
  • destination is the path you want to route to.
Gh05d
  • 7,923
  • 7
  • 33
  • 64
  • 1
    I think this is not what OP wants. It seems like he needs to rewrite requests based on some runtime data, he passing slug to some api and getting final destination in return and then rewrite happens. So you don't know destination in advance. – Danila Mar 12 '21 at 10:18
-1

Ok, I have a solution, it doesn't reload and it doesn't change the url.. however it requires some client side script.. as you see in the example below

Hope you find it to your liking :D

Here's my codesandbox

index.js(from your codesandbox)

import Link from "next/link";

export default function IndexPage() {
  return (
    <div>
      Hello World.{" "}
      <Link href="/something-slug">
        <a id="myElem">Go to slug pageee</a>
      </Link>
      <script
        dangerouslySetInnerHTML={{
          __html: `
          let elem=document.getElementById('myElem')
          elem.addEventListener('click',async function(event){
            event.preventDefault()
            console.log(event.path[0].href)
            let myFetch=await fetch(event.path[0].href)
            let text=await myFetch.text()
            let newHTML=document.createElement('html')
            newHTML.innerHTML=text
            let _next=document.getElementById('__next')
            _next.innerHTML=""
            let requestedNext=[...newHTML.getElementsByTagName('div')].filter(a=>a.id=="__next")[0]
            let scripts=[...requestedNext.getElementsByTagName('script')]
            scripts.forEach(a=>eval(a.innerHTML)) //eval any scripts sent by YOUR requested _next
            console.log(requestedNext)
            _next.innerHTML=requestedNext.innerHTML
          })
          `
        }}
      ></script>
    </div>
  );
}

slug.js(again, from your codesandbox)

export default function AboutPage() {
  return <div>About us</div>;
}

export async function getServerSideProps({ query, req, res }) {
  return {};
}
The Bomb Squad
  • 4,192
  • 1
  • 9
  • 17
  • what? how though? it works fine for me.. and it works fine for the asker.. can you elaborate? – The Bomb Squad Mar 13 '21 at 13:57
  • @Danila also.. look at the `__html` carefully before you say it will break things.. it will only load what you return to client side(not the whole list of other react things loaded to client side that you have no dealings with) – The Bomb Squad Mar 13 '21 at 14:00
  • 1
    Like first of all, this have nothing to do with OP question, even if he somehow approved bounty the question was about different topic. Second, what you've done actually breaks a lot of React code and Next data fetching too, basically all your hacks can be replaced with `Link` `as` property. Actually working example with server-side data fetching: https://codesandbox.io/s/httpsstackoverflowcomquestions66472986-02qpz – Danila Mar 13 '21 at 14:15
  • so your problem is that **YOU** didn't get the bounty? I just edited my question so you can't say "I'm keeping the minus because I can't remove it".. that's a good answer now why didn't you post your answer before me? I mean you can just edit that codesandbox to go to the "/something-slug" and u have a working answer – The Bomb Squad Mar 13 '21 at 14:20
  • 1
    I don't post an answer because I don't know an answer for OP question. He needs redirect from inside of `getServerSideProps` not from link click. – Danila Mar 13 '21 at 14:29
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/229863/discussion-between-the-bomb-squad-and-danila). – The Bomb Squad Mar 13 '21 at 14:30