Search code examples
vue.jsvuejs3vue-component

Why does Vue.js not update variables inside data


Can't update variables inside data in Vue

I'm creating a project using Vue 3 as frontend.

In Dashboard.vue, a GET request will be sent to backend with token in header, in order to let the backend identify user's identity, then Vue will receive the response with a json including info like this: {'uid': 'xxx', 'username': 'xxx'}.

My Dashboard.vue:

<script>
import axios from 'axios';

export default {
    data() {
        return {
            uid: '',
            username: '',
            temp: {},
            loaded: false
        }
    },
    methods: {
        require_get(url) {
            var token = localStorage.getItem('token');
            var config = {
                headers: {
                    'token': token,
                }
            };
            var _url = 'user/dashboard/' + url;
            axios.get(_url, config)
            .then(response => {
                this.temp = response.data;
            })
        },
        get_user_info() {
            this.require_get('info');
            this.uid = this.temp['username']; 
            this.username = this.temp['username'];
        }
    },

    mounted() {
        this.get_user_info();
    }
}
</script>

In this way, uid and username cannot be updated correctly.

For debugging, when I add console.log(this.uid) at the end of get_user_info() like this:

//...
this.require_get('info');
this.uid = this.temp['username']; 
this.username = this.temp['username'];
console.log(this.temp['uid']);

I get a undefined. But when I add console.log(this.uid) at the end of require.get() like this:

//...
.then(response => {
                this.temp = response.data;
                console.log(this.temp['uid]);
            })

The output shows that variable uid has already been updated at this moment.

After testing, I found that I can correctly update uid and username as long as I put

this.uid = this.temp['username']; 
this.username = this.temp['username'];

inside require_get(). Why is that? And how can I manage to update these variables with these two codes staying in get_user_info()?

Update

I changed my codes into"

    methods: {
        async require_get(url) {
            var token = localStorage.getItem('token');
            var config = {
                headers: {
                    'token': token,
                }
            };
            var _url = 'user/dashboard/' + url;
            axios.get(_url, config)
            .then(response => {
                return response.data;
            })
        },
        async get_user_info() {
            let info = await this.require_get('info');
            console.log(info);
            this.uid = info['username']; 
            this.username = info['username'];
        }
    },

    mounted() {
        this.get_user_info('info');
    }

and the output of console.log(info) is still undefined, now I don't understand...


Solution

  • The issue is asynchronous execution.

    In require_get, you update this.temp in the .then() callback, which is only called when the Promise has resolved. In get_user_info, you are calling require_get and then immediately (synchronously) trying to read the data. Because it is fetched and set asynchronously, it is not yet present and you get undefined.

    To fix it, make require_get an async function and return the data instead of using this.temp. Then make get_user_info an async function as well, await the call of require_get, and assign this.uid and this.username to the returned data.

    You could also use .then() if you prefer that to async/await. I have included examples for both.

    I assume that this.uid = data['username'] was meant to be this.uid = data['uid'], so changed that too.

    With async/await

    import axios from 'axios';
    
    export default {
        data() {
            return {
                uid: '',
                username: '',
                loaded: false
            }
        },
        methods: {
            async require_get(url) {
                var token = localStorage.getItem('token');
                var config = {
                    headers: {
                        'token': token,
                    }
                };
                var _url = 'user/dashboard/' + url;
                var response = await axios.get(_url, config);
                return response.data;
            },
            async get_user_info() {
                var data = await this.require_get('info');
                this.uid = data['uid']; 
                this.username = data['username'];
            }
        },
    
        mounted() {
            this.get_user_info();
        }
    }
    

    With .then()

    import axios from 'axios';
    
    export default {
        data() {
            return {
                uid: '',
                username: '',
                loaded: false
            }
        },
        methods: {
            require_get(url) {
                var token = localStorage.getItem('token');
                var config = {
                    headers: {
                        'token': token,
                    }
                };
                var _url = 'user/dashboard/' + url;
                return axios.get(_url, config).then((response) => response.data);
            },
            get_user_info() {
                this.require_get('info').then((data) => {
                    this.uid = data['uid']; 
                    this.username = data['username'];
                });
            }
        },
    
        mounted() {
            this.get_user_info();
        }
    }