Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Named route throws Cannot assign to read only property error #1381

Closed
parallelo3301 opened this issue Apr 27, 2017 · 9 comments
Closed

Named route throws Cannot assign to read only property error #1381

parallelo3301 opened this issue Apr 27, 2017 · 9 comments

Comments

@parallelo3301
Copy link

Version

2.5.2

Reproduction link

https://github.com/fandaa/vue-router-bug/commits/master

Steps to reproduce

  1. Clone repo
  2. npm i and npm run dev
  3. Navigate to http://localhost:8080/x and click on go to y

What is expected?

Browser navigated to route /y.

What is actually happening?

Getting TypeError: Cannot assign to read only property 'path' of object '#<Object>' as error.


You can try to start at http://localhost:8080/y and try to navigate to /x by clicking on links with go to x using as a prefix.

vue-router seems to not cooperate with [email protected], it works just fine within my project using [email protected].

The problem is only with named routes, you can try http://localhost:8080/a, where you can navigate to /b and vice-versa without any difficulty.

@parallelo3301
Copy link
Author

parallelo3301 commented Apr 28, 2017

By replacing this line https://github.com/vuejs/vue-router/blob/dev/dist/vue-router.esm.js#L1302 (source:
https://github.com/vuejs/vue-router/blob/dev/src/create-matcher.js#L56) to:

location = Object.assign({}, location, {
  path: fillParams(record.path, location.params, `named route "${name}"`),
})

it no longer throws an error. I don't have enough time to trace it more deeply now (why is .path not writeable), but I hope this is at least good starting point.

@posva
Copy link
Member

posva commented Apr 29, 2017

hey @fandaa can you simplify the example in a js fiddle, please: http://jsfiddle.net/posva/9r6xhqbp/

@parallelo3301
Copy link
Author

Hi @posva, I tried to simplify it at WebpackBin.

If you uncomment line 20 at main.js (name: 'a'), it will start throwing an error (if you are on /b and try to navigate to /a).
Also, what I found - if you at the same time comment line 47 (const matched = router.getMatchedComponents(to)) it will now work. So calling router.getMatchedComponents(to) causes the issue.

Also next thing, if you comment lines 20 (with name) and 47 (getMatched call) and append <router-link :to="{name:'a'}">go to a</router-link> to app.vue, there is an error Error in render function: "TypeError: Cannot read property 'regex' of undefined" - demonstrated in this bin - instead of something, which makes sense (eg. route named 'a' was not found).

Thanks for your time.

@parallelo3301
Copy link
Author

parallelo3301 commented Apr 30, 2017

@posva jsfiddle code.
Edit: also, it's not related to [email protected] version how I previously wrote.

@posva
Copy link
Member

posva commented Apr 30, 2017

Thanks, that's much better 🙂
For the moment, a workaround is passing a copy of the to object since the one in the navigation guards is read only. Something like {...to} or Object.assign({}, to) works. I'll check further to see where this should be done

@posva
Copy link
Member

posva commented Apr 30, 2017

When router.getMatchedComponents(location?) being used in a navigation guard the to is read only and therefore throws
@yyx990803 Is it better to say this in the docs or always do an assign to copy the to parameter in getMatchedComponents?

@remoe
Copy link

remoe commented Apr 30, 2017

I had a similarly error ( [email protected] [email protected] ) with the following callstack:


vue.esm.js:430 [Vue warn]: Error in callback for watcher "function () { return getter(this$1.state, this$1.getters); }": "TypeError: Cannot assign to read only property 'path' of object '#<Object>'"

(found in <Root>)

vue.esm.js:517 TypeError: Cannot assign to read only property 'path' of object '#<Object>'
    at Object.match (vue-router.esm.js:1302)
    at VueRouter.match (vue-router.esm.js:2305)
    at HTML5History.transitionTo (vue-router.esm.js:1663)
    at HTML5History.push (vue-router.esm.js:2056)
    at VueRouter.push (vue-router.esm.js:2373)
    at Vue$3.store.watch.sync (index.js:25)
    at Watcher.run (vue.esm.js:2833)
    at Watcher.update (vue.esm.js:2807)
    at Dep.notify (vue.esm.js:726)
    at Object.reactiveSetter [as route] (vue.esm.js:956)

handleError	@	vue.esm.js:517
run	@	vue.esm.js:2835
update	@	vue.esm.js:2807
notify	@	vue.esm.js:726
reactiveSetter	@	vue.esm.js:956
router/ROUTE_CHANGED	@	index.js:8
wrappedMutationHandler	@	vuex.esm.js:591
commitIterator	@	vuex.esm.js:315
(anonymous)	@	vuex.esm.js:314
_withCommit	@	vuex.esm.js:402
commit	@	vuex.esm.js:313
boundCommit	@	vuex.esm.js:269
(anonymous)	@	index.js:37
(anonymous)	@	vue-router.esm.js:1789
updateRoute	@	vue-router.esm.js:1788
(anonymous)	@	vue-router.esm.js:1665
(anonymous)	@	vue-router.esm.js:1774
step	@	vue-router.esm.js:1613
(anonymous)	@	vue-router.esm.js:1617
(anonymous)	@	vue-router.esm.js:1754
Promise.all.then	@	client-entry.js:62
router.onReady(() => {
  // Add router hook for handling asyncData.
  // Doing it after initial route is resolved so that we don't double-fetch
  // the data that we already have. Using router.beforeResolve() so that all
  // async components are resolved.
  router.beforeResolve((to, from, next) => {
    // https://github.com/vuejs/vue-router/issues/1381
    const route = Object.assign({}, to);
    const matched = router.getMatchedComponents(route)
    const prevMatched = router.getMatchedComponents(from)
    let diffed = false
    const activated = matched.filter((c, i) => {
      return diffed || (diffed = (prevMatched[i] !== c))
    })
    if (!activated.length) {
      return next()
    }
    //bar.start()
    Promise.all(activated.map(c => {
      if (c.asyncData) {
        return c.asyncData({ store, route: to })
      }
    })).then(() => {
      //bar.finish()
      next() // <<<<<<<<<<<<<<<<<< client-entry.js:62
    }).catch(next)
  })

@LinFeng1997
Copy link

I also meet the problem.@fandaa provide way can work.

@xgqfrms
Copy link

xgqfrms commented Mar 17, 2021

same question

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants