【问题标题】:VueJs Maximum call stack size exceededVueJs 超出最大调用堆栈大小
【发布时间】:2020-04-20 18:21:23
【问题描述】:

在过去的 3 天里,我一直在网上搜索,但找不到解决此问题的方法。当我打开我的页面时,它给出了这个错误:

ReferenceError: store is not defined
    at app.js:89294
    at iterator (app.js:71515)
    at step (app.js:71241)
    at runQueue (app.js:71249)
    at HTML5History.confirmTransition (app.js:71542)
    at HTML5History.transitionTo (app.js:71429)
    at VueRouter.init (app.js:72129)
    at Vue.beforeCreate (app.js:70598)
    at invokeWithErrorHandling (app.js:76676)
    at callHook (app.js:79027)

我设法将问题跟踪到我的 router.js 文件,但无法解决问题。我也尝试将我的商店文件导入路由器文件,但它返回 Maximum call stack size exceeded 错误。

代码

Router.js

import Vue from "vue";
import VueRouter from 'vue-router';
Vue.use(VueRouter);

import pageAbout from './components/About.vue';
import pageHome from './components/Home.vue';
import pageBooks from './components/Books.vue';
import pageChapters from './components/Chapters.vue';
import pageVerses from './components/Verses.vue';

import Dashboard from './components/admin/Dashboard.vue';
import Register from './components/auth/Register.vue';
import Login from './components/auth/Login.vue';

import passportclients from './components/passport/Clients.vue';
import passportauthorizedclients from './components/passport/AuthorizedClients.vue';
import passportpersonalaccesstokens from './components/passport/PersonalAccessTokens.vue';

import adminVerses from './components/admin/verses.vue';
import NotFoundComponent from './components/NotFoundComponent.vue';

const router = new VueRouter({
    mode: "history",
    routes: [
        {
            path: '*',
            name: '404',
            component: NotFoundComponent
        },
        // ADMIN ROUTES
        {
            path: '/dashboard',
            name: 'dashboard',
            component: Dashboard,
            meta: { requiresAuth: true },
            children: [
                {
                    path: '/verses',
                    name: 'adminVerses',
                    component: adminVerses,
                    meta: { requiresAuth: true }
                },
                {
                    path: '/passport-clients',
                    name: 'passport-clients',
                    component: passportclients,
                    meta: { requiresAuth: true }
                },
                {
                    path: '/passport-authorized-clients',
                    name: 'passport-authorized-clients',
                    component: passportauthorizedclients,
                    meta: { requiresAuth: true }
                },
                {
                    path: '/passport-personal-access-tokens',
                    name: 'passport-personal-access-tokens',
                    component: passportpersonalaccesstokens,
                    meta: { requiresAuth: true }
                }
            ]
        },

        // public routes
        {
            path: "/",
            name: 'home',
            component: pageHome
        },
        {
            path: "/about",
            name: 'about',
            component: pageAbout
        },
        {
            path: "/book/:slug",
            name: 'books',
            component: pageBooks
        },
        {
            path: "/book/:book_slug/:slug",
            name: 'chapters',
            component: pageChapters
        },
        {
            path: "/book/:testament_slug/:book_slug/:slug",
            name: 'verses',
            component: pageVerses
        },
        // auth
        {
            path: '/register',
            name: 'register',
            component: Register
        },
        {
            path: '/login',
            name: 'login',
            component: Login
        }
    ]
});

router.afterEach((to, from) => {
    Vue.nextTick(() => {
        document.title = to.pageTitle || 'Bible';
    });
});


router.beforeEach((to, from, next) => {
    var requiresAuth = to.matched.some( record => record.meta.requiresAuth );
    // when route requires auth and there's no current user, reidrect to '/login'
    if(!store.getters.isLoggedIn){
      next({name: 'login'});
    // when we go to login route and are already logged in, we can skip this page
    // so we redirect to the homepage
    } else if (to.path == '/login' && store.getters.isLoggedIn){
      next({name: 'home'});
    // if none of the above matches, we have a normal navigation that should just go through
    // so we call `next()`
    } else {
      next(); // you called `next('/')` which redirected to the homepage over and over again.
    }
});

export default router;

Store.js

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    status: '',
    token: localStorage.getItem('access_token') || '',
    type: localStorage.getItem('token_type') || '',
    user : {}
  },
  mutations: {
    auth_request(state){
        state.status = 'loading'
      },
      auth_success(state, type, token, user){
        state.status = 'success'
        state.token = token
        state.type = type
        state.user = user
      },
      auth_error(state){
        state.status = 'error'
      },
      logout(state){
        state.status = ''
        state.token = ''
        state.type = ''
      },
  },
  actions: {
    login({commit}, user){
        return new Promise((resolve, reject) => {
          commit('auth_request')
          axios({url: '/api/auth/login', data: user, method: 'POST' })
          .then(resp => {
            console.log('login data', resp);
            const token = resp.data.token
            const type = resp.data.token_type
            const user = resp.data.user
            localStorage.setItem('token', token)
            localStorage.setItem('token_type', type)
            axios.defaults.headers.common['Authorization'] =  'Bearer ' + token
            commit('auth_success', token, type, user)
            resolve(resp)
          })
          .catch(err => {
            commit('auth_error')
            localStorage.removeItem('token')
            reject(err)
          })
        })
    },
    register({commit}, user){
        return new Promise((resolve, reject) => {
          commit('auth_request')
          axios({url: 'api/auth/register', data: user, method: 'POST' })
          .then(resp => {
            console.log('register data', resp);
            const token = resp.data.access_token
            const type = resp.data.token_type
            const user = resp.data.user
            localStorage.setItem('access_token', token)
            localStorage.setItem('token_type', type)
            axios.defaults.headers.common['Authorization'] =  'Bearer ' + token
            commit('auth_success', token, type, user)
            resolve(resp)
          })
          .catch(err => {
            commit('auth_error', err)
            localStorage.removeItem('access_token')
            reject(err)
          })
        })
      },
      logout({commit}){
        axios.defaults.headers.common['Authorization'] = 'Bearer ' + this.state.token
        return new Promise((resolve, reject) => {
        axios({url: 'api/auth/logout', method: 'POST' })
          .then(resp => {
            commit('logout')
            localStorage.removeItem('access_token')
            localStorage.removeItem('token_type')
            delete axios.defaults.headers.common['Authorization']
            resolve()
          })
          .catch(err => {
            commit('logout')
            localStorage.removeItem('access_token')
            localStorage.removeItem('token_type')
            delete axios.defaults.headers.common['Authorization']
            reject(err)
          })
        })
      }
  },
  getters: {
    isLoggedIn: state => !!state.token,
    authStatus: state => state.status,
    LoggedUser: state => state.user,
  }
});

App.js

require('./bootstrap');
window.Vue = require('vue');

import Darkmode from 'darkmode-js';
import App from "./components/App";

import 'es6-promise/auto';
import axios from 'axios';
import VueAxios from 'vue-axios';
import VueRouter from 'vue-router';
import router from './router';
import Vuex from 'vuex';
import 'es6-promise/auto';
import store from './store';


// Set Vue globally
window.Vue = Vue
// Set Vue router
Vue.router = router;
Vue.use(VueRouter);
// Set Vue authentication
Vue.use(VueAxios, axios);
Vue.use(Vuex);

const token = localStorage.getItem('access_token')
if (token) {
  axios.defaults.headers.common['Authorization'] = 'Bearer ' + token
}

const app = new Vue({
    el: '#app',
    router,
    store,
    render: (h) => h(App)
});

App.vue(主要组件)

<script>
    export default {
        data() {
            return {
                user: ''
            }
        },
        computed : {
            isLoggedIn() {
                return this.$store.getters.isLoggedIn
            }
        },
        methods: {
            logout: function () {
                this.$store.dispatch('logout')
                .then(() => {
                    this.$router.push({name: 'home'})
                })
            }
        },
        created: function () {
            this.user = this.$store.state.user
        }
    }
</script>

问题

如何解决此错误?

更新

根据评论建议,我必须将我的商店导入router.js 文件,它会返回 Maximum call stack size exceeded 错误。

如何解决超出最大调用堆栈大小的问题?

【问题讨论】:

  • @JaromandaX 路由器不是一个组件。我不认为上面定义了this.$store
  • @mafortis 您应该更改标题。您知道如何解决not defined 问题。你真正的问题是堆栈溢出。
  • @JaromandaX 它返回TypeError: Cannot read property '$store' of undefined
  • @MarkMeyer 标题是我的错误信息 :) 你想让我改成什么? :D
  • 太糟糕了,错误消息没有堆栈跟踪,您可以追溯到代码中的特定行

标签: javascript vue.js vuejs2


【解决方案1】:

您的逻辑导致无限重定向到/login

试试下面的逻辑——我觉得是对的

router.beforeEach((to, from, next) => {
  var requiresAuth = to.matched.some(record => record.meta.requiresAuth);
  if (to.path != '/login' && !store.getters.isLoggedIn) {
    next({
      name: 'login'
    });
  } else if (to.path == '/login' && store.getters.isLoggedIn) {
    next({
      name: 'home'
    });
  } else {
    next();
  }
});

作为奖励,这就是我所说的 Promise 构造函数反模式

axios 返回一个 Promise ... 无需将其包装在新的 Promise 构造函数中

所以,例如,你的登录函数应该写成

login({commit}, user){
    commit('auth_request');
    return axios({url: '/api/auth/login', data: user, method: 'POST' })
    .then(resp => {
        console.log('login data', resp);
        const token = resp.data.token;
        const type = resp.data.token_type;
        const user = resp.data.user;
        localStorage.setItem('token', token);
        localStorage.setItem('token_type', type);
        axios.defaults.headers.common['Authorization'] =  'Bearer ' + token;
        commit('auth_success', token, type, user);
        return resp;
    })
    .catch(err => {
        commit('auth_error');
        localStorage.removeItem('token');
        throw err;
    });
}

【讨论】:

  • 可以防止超出的错误,但是我单击登录或注销等链接时会收到uncaught (in promise) 错误。它可能与这个 beforeeach 或其他东西有关吗? PS如果你想看我对错误loom.com/share/81807ff673e94b688b90d9c97c01c083进行屏幕录制
  • ncaught (in promise) 错误 - 肯定不止这些 - 如果没有,请使用能提供有意义错误的浏览器
  • 我想你已经看过我分享的视频了,我得到的只是Uncaught (in promise) undefined
  • 很明显,您的承诺代码中的某些内容正在尝试使用 undefined 的属性 - 您是否尝试过自己调试这个新问题?
  • 登录后重复重定向,一个在我的 beforeeach 中,一个在我的登录功能中。感谢您的帮助感谢它。
猜你喜欢
  • 2020-07-29
  • 2019-09-04
  • 2020-11-21
  • 1970-01-01
  • 2015-10-24
  • 2015-12-29
  • 2017-12-27
  • 2020-12-06
  • 2018-02-06
相关资源
最近更新 更多