Coco
Coco

Reputation: 1630

Single Page Web App that DOESN'T change url

OK, I know I'm going against conventional wisdom here, but here goes. I'm learning how to build a SPA using react and redux, and things are going well. I've incorporated react-router, because it seemed to be the accepted thing to do, but now I'm having issues. I want my SPA to act like a real app where the user will always come in at the landing page, and then go from there. As the user navigates from page to page, various things are fetched and stored. Some pages require authorization, for example, others don't. The problem is that when I use react router the URL changes at each route. So then, when the user comes back at a subsequent visit through say a bookmark, the app tries to jump to the page they left at, rather than at the entry point where I need them to go. This screws up a bunch of stuff underneath the hood and they get gobbledegook.

I've never really understood why it is conventional wisdom to "never break the back button" and always reflect everything the user does in the url. This seems like such a dogma, it's difficult to find ANY alternative ways of thinking. I have had times when I do a google search, for example, and go to a site where I click around for awhile, don't find what I'm looking for and then want to use the back button to go back to my google search results, but instead it goes click-click-click back through every step I made IN THAT SITE. Bleh. I eventually have to close that tab and start over. This happens to me all the time.

In mobile apps, the user is quite used to always arriving at a landing page, and clicking around from there. Why can't web apps act the same way?

So my question is: how would I implement that in a react-redux application? I have an internal "back" button that the user can click to go to a previous "page" within the app. I'm thinking I could keep the "history" in redux store, and write some goBack methods and such WHICH DON'T ALTER THE URL. Are there any examples that use this approach?

Any advice much appreciated.

Upvotes: 2

Views: 4505

Answers (2)

seveibar
seveibar

Reputation: 4943

As you said, it's probably not a good idea to go against the grain and create your own back button.

That said, if you don't want those features of react-router, it shouldn't be very difficult to implement your own router.

You could, for example, model your redux state with a history list,

{
  history: ["home"],
  home: { ... },
  otherPage: { ... },
}

Then in your top-level render function just determine the page and render,

import HomeComponent from 'components/HomePage'
import OtherPageComponent from 'components/OtherPageComponent'

const pages = {
    'home': HomeComponent,
    'otherPage': OtherPageComponent
}

export class App extends React.Component {
    ...
    render() {
        const CurrentPage = this.props.history[this.props.history.length-1];
        return (
             <CurrentPage />
        )
    }
}

export default App;

You'll then need a reducer/action to change routes,

// reducer.js
export default function reducer(state, action) {
    switch(action.type) {
        case 'CHANGE_ROUTE':
            return {
                ...state,
                history: state.history.concat([action.route])
            }
        case 'GO_BACK':
            return { 
                ...state,
                history: history.slice(0,-1)
            }
        default:
            return state
    }
}

// action.js
export const changeRoute = (route) => ({ type: 'CHANGE_ROUTE', route });
export const goBack = () => ({ type: 'GO_BACK'});

You could then change the route on any page by dispatching the relevant action,

// some-component.js
import { goBack, changeRoute } from 'action.js'

...
// in some render method

<button onClick={() => dispatch(goBack())}>
    Go Back
</button>
<button onClick={() => dispatch(changeRoute('somePage'))}>
    Go to some page
</button> 

You would probably want to package the onClick stuff together in some kind of <Link> component like react-router.

Good luck!

Upvotes: 2

rasmeister
rasmeister

Reputation: 1996

There are two challenges with what you propose. First, is that without URL's, the user cannot bookmark their location. And second, the app is operating within a browser window and the browser window has a back button (and forward, and history).

I am working on a SPA that after the initial bootstrap only ever makes JSON requests through a RESTful api. This works beautifully but does require extra work to manage the page history. Without it users get frustrated that they are 'exited' from the application back to the login page when they hit the 'back' button in the browser.

The page history we maintain, however, is one we control and so it can be managed to the granularity we want. There are many api calls that don't change the URL. Unfortunately, with many frameworks they expect you to operate within a 'page' mindset, hopefully something that will change soon. (Personally, I am contemplating just disabling the back button so the user views it more as an application.)

I think the point that you are making, and with which I agree is that we are building applications and being constrained to the 'traditional' concept of pages makes the concept of "SINGLE page application" somewhat less than what it should be.

Upvotes: 2

Related Questions