Giter Club home page Giter Club logo

mobx-router's Introduction

Twitch Twitch Discord Youtube Twitter

๐Ÿ™‹โ€โ™‚๏ธ Made by @thekitze

Other projects:

  • ๐Ÿ’ป Sizzy - A browser for designers and developers, focused on responsive design
  • ๐Ÿซ React Academy - Interactive React and GraphQL workshops
  • ๐Ÿ”ฎ Glink - Changelogs, Roadmap, User Requests
  • ๐Ÿถ Benji - Ultimate wellness and productivity platform
  • ๐Ÿค– JSUI - A powerful UI toolkit for managing JavaScript apps
  • ๐Ÿ“น YouTube Vlog - Follow my journey

Zero To Shipped

mobx-router's People

Contributors

aap82 avatar bennichols avatar danistefanovic avatar dependabot[bot] avatar kitze avatar nareshbhatia avatar rdrg avatar takanori-s avatar thdk avatar tobiaszcudnik avatar tomaash avatar vcinly avatar vencax avatar volch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mobx-router's Issues

API clarifications - use of MobX stores

@kitze and other contributors, thanks for this awesome project! I spent my whole day yesterday switching over a significant application from react-router to mobx-router. I was having subtle data loading issues with react-router, which are now gone by taking the pure state-driven approach by mobx-router.

I'd like to share a couple of experiences when porting over to mobx-router and also a few questions. Hope these will help improve the documentation for future users.

Name of the root store
It was not clear from the docs that mobx-router expects the name store for the MobX store supplied to the Provider. I initially tried to use a more descriptive name like this: <Provider rootStore={rootStore}>, which did not work and was difficult to debug because of obscure error messages.

Usage of root store
I am not entirely sure how the mobx-router uses the store and why it needs the entire root store instead of just its own RouterStore? If the idea was to expose the entire rootStore to it, then why does the goTo() method require a store parameter? mobx-router should be able to use the root store that it knows about.

Creation of the root and router stores
Following the pattern described in MobX documentation, I generally define a root store like this:

class RootStore {
    constructor() {
        this.userStore = new UserStore(this);
        this.todoStore = new TodoStore(this);
    }
}

Extending this example, I think it makes sense to pass the root store to the RouterStore like this:

class RootStore {
    constructor() {
        this.userStore = new UserStore(this);
        this.todoStore = new TodoStore(this);
        this.routerStore = new RouterStore(this);
    }
}

I used the name this.routerStore instead of this.router to clearly make the distinction between the router vs. the router store.

Passing root store to mobx-router
I assume that the official place to hand off the rootStore to the mobx-router is the call to startRouter, is this correct?

startRouter(views, store);

Also IMHO, the first parameter should be called routes - what we are passing in is a map of routes, not views. This will immensely clarify the usage pattern for newbies.

Thanks in advance for your thoughts on these questions and suggestions.

I am really excited to contribute back to this project. @kitze, I see that the last commit to this repo was back in August. I am sure you are busy, but any idea when you are going to be active again? Thanks for this wonderful work!

Server Side Rendering

Hello @kitze

mobx-router is very cool, great work!

I would like to replace react-router in my projects but I need SSR support.

Is this in your roadmap?

Thank You.

Include the target route in `beforeExit`

I need to know what the target route is going to be in beforeExit. There are a few use cases for this, like conditionally allowing navigation only between certain routes, or conditionally running cleanup of state if we know it won't be needed on the next page (but leaving it if it is needed, such as in a child routing situation). For now, I can accomplish this by caching the previous view in beforeExit and moving the logic to beforeEnter, but this seems wasteful and kinda dirty.

I'm pretty sure I can do this trivially by just additionally passing view (and maybe even paramsObj and queryParamsObj) on this line:

const beforeExitResult = (rootViewChanged && this.currentView && this.currentView.beforeExit) ? this.currentView.beforeExit(this.currentView, currentParams, store, currentQueryParams) : true;

Thoughts?

Allow router.goTo to find route based on string

Having to pass the actual Route component instance to router.goTo is really inconvenient. What if the router views object took an optional name (defaulting to the views object key name) for each route that could be used in router.goTo instead of passing the Route instance explicitly? This would also be handy when you need to pass a specific route via a query string.

Bug when beforeEnter doens't return false

To reproduce;

Use the example mobx router repo

In src/config/views.js

update the book route with a beforeEnter property like below

book: new Route({
    path: '/book/:id/page/:page',
    component: <Book/>,
    onEnter: (route, params, store) => {
      console.log(`entering book with params`, params);
      store.app.setTitle(route.title);
    },
    beforeEnter: (route, params, store) => {
      return true;
    }
  })

run the demo app and follow the below navigation path:

  1. Go to book 250, page 130
  2. Home
  3. Go to book 250, page 130

I get the below error here:

image

Book component uses the params property of the router, however, they are undefined for a very short time. I mean, when I check the params property for undefined before accessing it's values, the example app works again.

See below the "workaround" for the Book component:

class Book extends Component {
  render() {
    const {store} = this.props;
    const {router: {params}} = store;

    return (
      <div>
        <h1> Book {params && params.id} </h1>
        <h3> Page: {params && params.page} </h3>
      </div>
    );
  }
}

Question

Before I say anything there are two things you must know: 1) I have no professional background in programming, web design, theory, or anything having to do with code. I'm purely self taught (less than 8 months) in this regard. Second, I've had quite a bit of scotch (half bottle of Macallan 12-year) this evening, this after a few bottles of wine; so I may have missed something obvious, and I truly apologize if that may be the case.

But, is there a reason you're passing all of the stores (the entire store object) around with the router store and its routing functions? I'm asking because in your example you placed the component as a child of Provider, thereby allowing it and every component that so chooses to gain mobx store access through context (@observerable).

So, if I may offer a feature request: removing the single store concept and passing multiple stores to the component through rest properties , allowing mobx-router to pick up the router store, and then, in the view config section, one could provide an array of stores for each route. (I saw how this is currently passed to director.js, but can easily be stripped out, no?).

Why an array of stores? Then you could easily write a higher order component and decorate each of the routes/components with only the stores they need that have been defined.. For some reason, I thought this would make the whole application easier to reason about.

But I know i'm coming from a different place here. I don't work for a tech company, and I don't write tests or comments, but for I like mobx, and I read Michael's article, and it made sense. So, thank you.

Mobx state persistance between routes

Hi, I supose it is not the place to post this question but I need a quick answer.
Mobx state can persist between routes changing with mobx-state-router ?
That's mostly what I'm looking for
Thank's

a bit lose with the samples, getting error store.router is undefined

Hi!!..I'm trying to use mobx-router with this boilerplate unfortunately I'm a bit lose because seems than this sample use an older version of mobx-router and I'm a bit noob using mobx

The file structure between the sample and the boilerplate is similar, my App.js ooks like this

// @flow

import React, {PropTypes} from 'react'
import { observer } from 'mobx-react'

import MyComponent from './MyComponent'
import { Provider } from 'mobx-react'
import views from './../config/views'
import Store from './../stores/Store'

import {MobxRouter,startRouter} from 'mobx-router'

const store = new Store()
console.log('store es ' + store.router); //====> undefined

startRouter(views,store)

@observer
class App extends React.Component {
  render() {
    return (
      <Provider store={store}>
        <MobxRouter></MobxRouter> 
      </Provider>
      
    )
  }
}


export default App

and the Store looks like this, I add the router parameter because I look this in the readme

import { observable, computed } from 'mobx'
import {routerStore} from 'mobx-router'

class Store {
  //Autorun is a function from MobX that runs everytime that something inside is
  //updated. In the example below, everytime 'numClicks' is updated, autorun will run
  //the console.warn
  //
  // import {autorun} from 'mobx'
  // constructor() {
  //   autorun(() => console.warn('MobX autorun - Whenever numClicks has it value updated, console.log runs: ', this.numClicks))
  // }

  name = 'Reaxor';
 //this router is generating me troubles!!!!
  router = routerStore; //must be an observable??

  description = 'boilerplate for better state management, styling, testing and cleaner code';
  @observable numClicks = 0;

  @computed get oddOrEven() {
    return this.numClicks % 2 === 0 ? 'event' : 'odd'
  }



  clickButton = () => {
    this.numClicks++
  }
}

export default Store

the import {routerStore} from 'mobx-router' is generating troubles, mobx-router includes this field?...I install mobx-router with the typical npm install mobx-router --save

thank you

undefined store after goTo

I want go to auth page if not authenticated automatic, then go to home page if already authenticated

my views looks like

const views = {
    home: new Route({
        path: '/',
        component: <Home />,
        beforeEnter: (route, param, store) => {
            const isAuthenticated = store.user.isAuthenticated
            if (!isAuthenticated) {
                console.log("not authenticated")
                store.router.goTo(views.auth)
            }
            return isAuthenticated
        }        
    }),
    auth: new Route({
        path: '/auth',
        component: <Auth />, 
        beforeEnter: (route, param, store) => {
            const isAuthenticated = store.user.isAuthenticated
            if (isAuthenticated) {
                console.log("already authenticated")
                store.router.goTo(views.home)
            }
            return !isAuthenticated
        }
    })
}

I got an error after goto auth from home, How can I solve it ?

ร—
Unhandled Rejection (TypeError): Cannot read property 'user' of undefined
Route.beforeEnter
src/router/index.js:21
  18 | path: '/auth',
  19 | component: <Auth />, 
  20 | beforeEnter: (route, param, store) => {
> 21 |     if (store.user.isAuthenticated) {
  22 |         store.router.goTo(views.home)
  23 |     }
  24 | }
View compiled
โ–ถ 11 stack frames were collapsed.
Route.beforeEnter
src/router/index.js:12
   9 | component: <Home />,
  10 | beforeEnter: (route, param, store) => {
  11 |     if (!!!store.user.isAuthenticated) {
> 12 |         store.router.goTo(views.auth)
  13 |         return false
  14 |     }
  15 | }        
View compiled
โ–ถ 22 stack frames were collapsed.
./src/index.js
src/index.js:19
  16 |     router: new RouterStore()
  17 | }
  18 | 
> 19 | startRouter(views, store)
  20 | 
  21 | 
  22 | ReactDOM.render(

Thanks

Component Reference for route hooks

Hello,

Will it be possible to provide the component reference in the route hooks?

A reference to the component can give the ability to do animated routes.

Wrapping view in extra div

While migrating over to mobx-router, I noticed my views are getting wrapped in a <div> and causing a layout styling problem. Is this extra div necessary? If so would it be possible to provide at least a prop for adding custom styles to it?

A Link component

Add a convenient Link component like React Router that simply calls goTo.

Outdated mobx

image

Package json has mobx version specified explicitly, maybe allow newer versions? (i.e. `^2.5.1 insted if '2.5.1').
Because current state results in mobx being included twice.

<Link> Usage

Hey,

first of all thanks a lot for mobx-router. It works very nicely :)

One thing I couldn't really figure out though was how to use the <Link> properly. How to import & pass a view? Is there any documentation on this available?

thanks a lot for your help :)

Style Active Link

We should have a way to easily mark a Link component as "active" if it is a link for the current viewing (including params and queryParams).

With styled components I've been experimenting with something like this (note that this approach doesn't yet take into account params or queryParams):

const active = (activeStyle) => ({
  default: (defaultStyle) => (props) => {
    const { router, view } = props
    const isCurrent = router.currentView === view

    return isCurrent ? activeStyle : defaultStyle
  }
})

const StyledLink = styled(Link)`
  width: 70px;
  height: 70px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 250ms ease;
  background: ${
    active('linear-gradient(-42deg, #D264C6 0%, #FB4078 100%)')
    .default('none')
  };
`

indexRoute and childRoutes

Hello,
in the example routes configuration you use a structure that is a bit different from the react-router plain routes config.

In your case how would we specify routes hierarchies and how to use indexRoute and childRoutes?

Why not to reuse the react-router config structure?

Edit: sorry I thought the project depended on react-router, but I guess it's not the case.

falsy (ie `0`) param values are being ignored

for example I have a route path mentor/:id
So /mentor/1 works fine
/mentor/0 (with id=0) is replaced as /mentor

So I suggest changing newPath = value ? newPath.replace(paramKey, value) : newPath.replace(/${paramKey}, ''); with a null \ undifned check

route.js, line 57 as for master branch

I can make a PR, but that might be too much for 1 line

`beforeEnter` can't return `true` when mobx strict-mode is enabled

MobX reports that the route is being updated outside of an @action, error on line 64:

transaction(() => {
    this.currentView = view;
    this.params = toJS(paramsObj);
    this.queryParams = toJS(queryParamsObj);
});

mobx-router version 0.0.17

Full error from the console:

action 'goTo' 
mobx.module.js:98 Uncaught (in promise) Error: [mobx] Since strict-mode is enabled, changing observed observable values outside actions is not allowed. Please wrap the code in an `action` if this change is intended. Tried to modify: [email protected]
    at invariant$$1 (mobx.module.js:98)
    at fail$$1 (mobx.module.js:93)
    at checkIfStateModificationsAreAllowed$$1 (mobx.module.js:1088)
    at ObservableValue$$1../node_modules/mobx/lib/mobx.module.js.ObservableValue$$1.prepareNewValue (mobx.module.js:695)
    at ObservableObjectAdministration$$1../node_modules/mobx/lib/mobx.module.js.ObservableObjectAdministration$$1.write (mobx.module.js:3553)
    at RouterStore.set [as currentView] (mobx.module.js:3776)
    at router-store.js:178
    at transaction$$1 (mobx.module.js:2616)
    at RouterStore._callee$ (router-store.js:177)
    at tryCatch (runtime.js:62)
    at Generator.invoke [as _invoke] (runtime.js:296)
    at Generator.prototype.(anonymous function) [as next] (http://localhost:8001/static/js/bundle.js:138587:21)
    at step (asyncToGenerator.js:17)
    at asyncToGenerator.js:28

Interceptable Link

I use the Link component and it's awesome. But there's no way I can intercept that click.
In particular, depending on some programmatic logic I'd like to do some things in the onClick that may or may not cancel the click. For example:

<Link
    view={views.podcast}
     params={{id: podcast.id, slug: podcast.slug}}
     store={store}

     // pseudo code!
      onClick={e => {
          if (someCondition) {
            store.app.something = 'foo'
            return false
          } 
      }}
     >
   Click Here
</Link>

It's always a bit weird to have multiple onClick events because it's confusing what the order is supposed to be.

Here's a hack I wrote for my own needs. This works well:

export const InterceptableLink = ({
  view,
  className,
  params = {},
  queryParams = {},
  store = {},
  refresh = false,
  style = {},
  children,
  title = children,
  router = store.router,
  onClick = null,   // THIS IS NEW
}) => {
  if (!router) {
    return console.error('The router prop must be defined for a Link component to work!')
  }
  return (<a
      style={style}
      className={className}
      onClick={e => {

        // THESE LINES ARE NEW
        if (onClick && onClick(e) === false) {
          e.preventDefault();
          return;
        }
        // END NEW LINES

        const middleClick = e.which === 2;
        const cmdOrCtrl = (e.metaKey || e.ctrlKey);
        const openinNewTab = middleClick || cmdOrCtrl;
        const shouldNavigateManually = refresh || openinNewTab || cmdOrCtrl;

        if (!shouldNavigateManually) {
          e.preventDefault();
          router.goTo(view, params, store, queryParams);
        }
      }}
      href={view.replaceUrlParams(params, queryParams)}>
      {title}
    </a>
  )
}

Do you think that's a good idea? If so, I can clean it up in the form of a PR.

Documentation

Hello, I've tried to dive into your code and many things do not work as expected or as presented in the docs. I like this project but I guess the doc is not up to date.
An example is the router.goTo(views.book) generates a view.replaceUrlParams is not a function because the goTo method expect more parameters to be passed to it.

Another example is how we start the router, see #17.

Is this project maintained, meaning I could invest some time diving into it also to help you somehow or was this just a weekend experiment?

BTW: director is unmaintained, last commit was done 2 years ago, check this out: https://github.com/CodeYellowBV/tarantino

Nested routes?

First of all, thank you for mobx-router!
I've been facing an issue with nested routes... My case is I have an index.js file, where I set up a router to render /login and /app. After the user logs in, I redirect him to /app route. Pretty simple.

The problem is my app component has a sidebar with menu items in it and renders some content (next to the sidebar). I have a /posts item and a /user item (and posts/:id in the future). My first approach was to build another router to deal with this "internal" routes, but I reckon this isn't the best way to deal with it. I was looking for something more generic like react-router, that provides nested routes. So I would have in one views.js file something like this:

const views = {
  login: new Route({
    path: "/",
    component: <LoginContainer />
  }),
  app: new Route({
    path: "/app",
    component: <AppContainer />,
    beforeEnter: (route, params, store) => {
      if (!_verifyUserLogged(store.userStore)) {
        store.router.goTo(indexViews.login);
        return false;
      }
    }
  }),
  postList: new Route({
    path: "/app/post-list",
    component: <PostContainer />
  }),
  users: new Route({
    path: "/app/users",
    component: <UsersContainer />
  })
...

And render the app component, that has a sidebar, alongside with either the PostContainer or UserContainer depending on user navigation.

Is this possible or do I have to separate the routers?

Multiple stores

Is it possible to use this package with multiple stores? Or do you need a "root" store like in your examples?
I'd rather not have just a single store available for injecting like your example export default observer(['store'], Gallery);

My current setup with ReactRouter is along these lines (from memory so syntax might be off..)

export {
  userStore,
  imageStore,
}
import * as stores from "stores"

<Provider {...stores}>  
    <Route />  
</Provider>, document.getElementById('root')

I couldn't get the startRouter to work with this type of setup. Any input?

Router params change is not triggering a re-render of my view

I enter the following path in the browser:

/orders/123/summary

Everything works, the summary tab is rendered. Now I click on the detail tab. The path changes to:

/orders/123/detail

Nothing changes in the view! The render method is not triggered even though I am dereferencing router.params. Here's my code (simplified):

render() {
    const { store } = this.props;
    const { router: { params } } = store;
    const { orderId, tab } = params;

    console.log('render: ', tab);

    return (
        <div>
            {tab === 'summary' && <Summary />}
            {tab === 'detail' && <Detail />}
        </div>
    );
}

Here's the corresponding route:

order: new Route({
    path: '/orders/:orderId/:tab',
    component: <OrderPage />,
    onEnter: (route, params, store) => {
        console.log('------------> order.onEnter: ', params);
    },
    onParamsChange: (route, params, store) => {
        console.log('------------> order.onParamsChange: ', params);
    }
})

I can see onEnter and onParamsChange being triggered in my route, however that should not matter. The change in tabs should not retrigger a fetch - all I need is to change the view. However puzzled why the view is not reacting to a change in router.params. I confirmed that it is a MobX @observer. What am I doing wrong?

Thanks in advance.

Code splitting

Just opening as I'm curious. This seems to require System.import and some sort of lazily require'd components from what I've seen.

History Manipulation

Great work on this project! I've created a similar project (https://github.com/eugenkiss/static-mobx-routing) and I'm comparing the different approaches we took to see if there are things to improve.

Consider the following use case. You are on the homepage (/). You enter the route /new-post and create a new post. This leads you to route /post/12. When you now press the browser's back button you go back directly to / instead of /new-post. The reason I find this intuitive is that the new post became the post with the id 12 and therefore it makes sense to replace the history entry /new-post after successfully having created a post. You can see this working in my demo project: http://static-mobx-routing.surge.sh/

How would you suggest implementing this use case with mobx-router?

PropTypes error

I've added mobx-router to a project and started getting a new error:

Warning: You are manually calling a React.PropTypes validation function for the
`mobxStores` prop on `MobXStoreInjector`. This is deprecated and will not work
in the next major version. You may be seeing this warning due to a third-party
PropTypes library. See https://fb.me/react-warning-dont-call-proptypes for details.

The key for this seems to be trying to render the <MobxRouter /> component; the contents of the views, or whether I even call startRouter seems to have no impact.

I'm at a bit of a loss as to how to resolve this.

allow configuration without html5history, aka hash routing

As of now, mobx-router forces you to use html5history routing w/ pushState, however this isn't always desirable with SPA or when using Electron.

Would you accept a pull request that provides an option to switch to hash-based routing which would then use setRoute instead of pushState?

Scroll Position Restoration

Restoring the scroll position in SPAs seems to be a difficult problem in general. Mainly, because data is loaded asynchronously again when you go back. See, e.g., https://brigade.engineering/maintaining-scroll-positions-in-all-browsers-a280d49bffca.

Do you have ideas how you would adjust mobx-router so that it can support scroll position restoration? Or some other transient UI-specific state (e.g., hidden/opened UI elements) that you don't want to encode as query parameters?

React warns deprecated

When using mobx-rotuer, React library gives me those warrnings:

lowPriorityWarning.js:40 Warning: Accessing PropTypes via the main React package is deprecated, and will be removed in  React v16.0. Use the latest available v15.* prop-types package from npm instead. For info on usage, compatibility, migration and more, see https://fb.me/prop-types-docs
lowPriorityWarning.js:40 Warning: Accessing createClass via the main React package is deprecated, and will be removed in React v16.0. Use a plain JavaScript class instead. If you're not yet ready to migrate, create-react-class v15.* is available on npm as a temporary, drop-in replacement. For more info see https://fb.me/react-create-class

Is there any way how to solve them? It seems like mobx-router is using react the outdated way...

Async beforeEnter and beforeExit

As documented in the Readme, allowing async beforeEnter and beforeExit hooks would be a nice feature to support.

I started implementing it here -> https://github.com/timkendall/mobx-router/tree/feat/async-hooks

While the basic implementation is done (needs test coverage), I did notice one edge case we will need to handle - if a route entry is scheduled, there needs to be a way to cancel it (i.e before the async hooks resolve).

Another issue to think about - should this lib keep track of if a route is in the "loading" state (i.e if an async hook is resolving)? Or should we letter consumers do that?

@kitze thoughts?

Is this idiomatic ?

I want to redirect an unauthorized user if he's deep linking into a private path without credentials.

This is working, but I'm wondering if it's the best way to do it.

const views = {
    home: new Route({ path: '/', component: <Home /> }),
    perms: new Route({
        path: '/private',
        component: <Private />,
        beforeEnter: (route, params, store) => {
            if (!store.app.isAuthorized) {
                store.router.goTo(views.home)
                return false
            }
        }
    })
}

Is it possible to have autoruns subscribing to router properties?

Currently, the object we get from new RouterStore has observable objects that can't be observed by themselves. For example, something like the following doesn't seem to trigger if the currentPath or the params change:

let router = RouterStore()
// creating the routes and calling startRouter
autorun(() =>{
  console.log(router.params)
  console.log(router.currentPath)
})

The sites where we've been using this project work properly, but this is something we would like to have. Are we missing something?

Thank you all for the effort put into this project ๐Ÿ‘

Why doesn't goTo() sometimes trigger my view rendering?

I don't know if this is a bug in mobx-router or my misunderstand or a bug in my prototype.

My code looks something like this:

// This is component Home

  startSearch(q) {
    // this.props.store.app.setSearch(q)
    console.log("Doing a goTo with", q);
    this.props.store.router.goTo(views.search, {q: q}, this.props.store)
  }

  onSubmit(event) {
    event.preventDefault()
    let q = this.refs.q.value.trim()
    this.startSearch(q)
  }
  render() {
    ...
    <form action="" onSubmit={onSubmit}>
     <input type="search" ref="q" placeholder="Something something..." />
    </form>
    ...
  }

And the route config looks like this:

const views = {
  home: new Route({
    path: '/',
    component: <Home/>,
    onEnter: (route, params, store) => {
      console.log('Entering Home');
      store.app.results = null
      store.app.search = null
    }
  }),
  // Note that the views.search view shares the same component as views.home
  search: new Route({
    path: '/q/:q',
    component: <Home/>,
    onEnter: (route, params, store) => {
      console.log("ENTERING Search", params.q);
      // Use params.q to trigger a remote fetch of search results
    }
  }),
  ...

So when I'm on the route / and trigger that onSubmit which triggers the router.goTo(views.search, ...) it works. The onEnter for view search does run.

However, when I'm already on the view search and trigger the same onSubmit and router.goTo(views.search, {different: parametersthistime}, ...) then it does NOT render the view. I.e. that little console.log("ENTERING Search", params.q); does NOT happen. The URL in the address bar changes but no new onEnter.

Is this because the view name is unchanged?

beforeEnter params and queryParams

If I type in the browser address bar: http://localhost/home?foo=bar

and I have this route code:

    home: new Route({
      path: '/home',
      component: <Home />,
      beforeEnter: (route, params, store, queryParams ) => {
	if ( store.ux.isAuthenticated ) return true;
	console.log( 'route:', route, 'params:', params, 'query:', queryParams );
	store.router.goTo( views.login );
	return false;
      }

"params" is an empty JSON object and queryParams seems like it is an observable. But I cannot seem to get to the query params ( foo=bar ).

What I want to do is to implement "pass-thru" authentication. The login component needs to "goTo" the original attempted path, in this case "/home?foo=bar".

What am I doing wrong?

Adding support for html5history:false

This should address scenarios like #5 where the underlying server doesn't support deep linking.

Here's a hardcoded mockup that sets it to false and updates autorun.

...
const createDirectorRouter = (views, store) => {
  new Router({
    ...viewsForDirector(views, store)
  }).configure({
    html5history: false
  }).init('/');
};

const startRouter = (views, store) => {
  //create director configuration
  createDirectorRouter(views, store);

  //autorun and watch for path changes
  autorun(() => {
    const {currentPath} = store.router;
    const hash = `#${path}`;
    if (path !== window.location.hash) {
      window.history.pushState(null, null, hash);
    }
  });
};

export default startRouter;

Use the react context instead of provider/inject

From the docs of mobx regarding the mobx-react package, using Provider/Inject isn't recommended anymore. They sugest to use the React API context.

Using react context api will drop the need for mobx-react (which provides inject/provider) and allow to use mobx-react-lite. A smaller and faster version of mobx-react. (Its in fact a dependency of mobx-react)

I can do a pr for this one but I see two options:

  1. simply export MobxRouterBase component next to the already exported MobxRouter component.
  2. Breaking change: Drop the existing MobxRouter and rename (and export) MobxRouterBase to MobxRouter

I would prefere version 2

Back-button style go back

There are times when, in one component, I know for certainty that the user came from another component. And in the component they're in now I want to have a <a>Go back</a> link.
But I want to make the HTML be right-clickable.

This sort of works:

/* This is in the search result component, links back to the search resultS */
<Link view={views.search} params={{q: store.search_term_used}} store={store}>Go Back</Link>

It gets rendered out to:

<a href="/search/Search+Term+Used">Go Back</a>

But when you click that, it loads the page as a "new page" (not like a brand new browser request, it still has the onClick from mobx-router) and doesn't remember where you have scrolled down to.

If instead, I click the browser back button, it all looks the same except my browser knows how far down I was scrolled.

This sort of works:

/* This is in the search result component, links back to the search resultS */
<a href="#" onClick={(e) => this.goBack(e)}>Go Back</a>

And in that handler I can call regular history.back().

However, I now lack the nice href="..." that would make that Go Back link right-clickable.

I tried this:

/* This is in the search result component, links back to the search resultS */
<Link view={views.search} params={{q: store.search_term_used}} store={store}
  onClick={this.goBack}>Go Back</Link>

but it doesn't trigger "my" onclick but instead that of mobx-router.

Another, less desirable option is to do this:

/* This is in the search result component, links back to the search resultS */
let routeUrl = `/search/${store.search_term_used}`
<a href={routeUrl) onClick={(e) => this.goBack(e)}>Go Back</a>

...but I'd love to use something out of mobx-router to get that URL instead of having to create it as a string myself.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.