【发布时间】:2021-04-19 02:59:22
【问题描述】:
我在 vuex 模块中调用天气 API。我想要完成的是使用组件中的计算属性来获取数据。 使用当前设置,除了我需要刷新/重新加载页面以更新 vuex 状态外,没有任何问题。我已经尝试调度在已安装的钩子中获取数据的操作,但这也不起作用,因此必须手动重新加载页面才能为计算的属性分配数据。 这样做的正确方法是什么?
Vuex store.js
import Vue from 'vue';
import Vuex from 'vuex';
import {
Auth
} from 'aws-amplify';
import axios from 'axios';
var AWS = require('aws-sdk');
var AWSCognito = require('amazon-cognito-identity-js');
Auth.currentUserInfo
var data = {
UserPoolId: '******************',
ClientId: '******************',
},
userPool = new AWSCognito.CognitoUserPool(data);
var cognitoUser = userPool.getCurrentUser();
AWS.config.region = '******************';
Vue.use(Vuex);
const weatherService = {
state: () => ({
error: null,
currentTemp: '',
minTemp: '',
maxTemp: '',
sunrise: '',
sunset: '',
pressure: '',
humidity: '',
wind: '',
overcast: '',
name: '',
latitude: '',
longitude: '',
}),
mutations: {
SET_WEATHER_DATA(state, payload) {
state.currentTemp = payload.main.temp;
state.minTemp = payload.main.temp_min + '°C';
state.maxTemp = payload.main.temp_max + '°C';
state.pressure = payload.main.pressure + 'hPa';
state.humidity = payload.main.humidity + '%';
state.wind = payload.wind.speed + 'm/s';
state.overcast = payload.weather[0].description;
state.sunrise = new Date(payload.sys.sunrise * 1000)
.toLocaleTimeString('en-GB')
.slice(0, 5);
state.sunset = new Date(payload.sys.sunset * 1000)
.toLocaleTimeString('en-GB')
.slice(0, 5);
state.name = payload.name;
},
},
actions: {
getWeather({
commit
}) {
try {
if (cognitoUser != null) {
cognitoUser.getSession(function(err, session) {
if (err) {
console.log(err);
return;
}
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: '******************',
Logins: {
// Change the key below according to the specific region your user pool is in.
'cognito-idp.******************.amazonaws.com/******************': session
.getIdToken()
.getJwtToken(),
},
});
AWS.config.credentials.get(function(err) {
if (!err) {
var id = AWS.config.credentials.identityId;
// Instantiate aws sdk service objects now that the credentials have been updated
var docClient = new AWS.DynamoDB.DocumentClient({
region: AWS.config.region,
});
var params = {
//
};
params.ProjectionExpression = "user_meta_data";
docClient.query(params, function(err, data) {
if (err) console.error(err);
else {
console.log(data);
const lat = data.Items[0].user_meta_data.coordinates.latitude
const long = data.Items[0].user_meta_data.coordinates.longitude
axios
.get(
'https://api.openweathermap.org/data/2.5/weather?lat=' +
lat +
'&lon=' +
long +
'&units=metric&APPID=' +
process.env.VUE_APP_OPEN_WEATHER_API_KEY
)
.then((response) => {
commit('SET_WEATHER_DATA', response.data)
console.log("dispatched!")
})
.catch((error) => {
console.log(error);
});
}
});
}
});
});
}
} catch (e) {
console.log(e);
return;
}
}
},
getters: {
weatherGetter(state) {
return state
},
},
};
const store = new Vuex.Store({
modules: {
w: weatherService
},
state: {
//
},
mutations: {
//
},
actions: {
//
},
getters: {
//
},
});
export default store;
Weather.vue 组件
<template>
<!-- <div>
<v-card> {{ weatherGetter }} </v-card>
</div>
</template>
<script>
export default {
data() {
return {
};
},
computed: {
weatherGetter() {
return this.$store.getters('weatherGetter');
},
},
mounted() {
this.$store.dispatch('getWeather');
};
</script>
我查看了其他类似的问题,他们似乎建议使用 beforeRouteEnter,我认为这在我的情况下并不理想。 我还尝试在 main.js 中创建的钩子中调度操作,但无济于事。
【问题讨论】:
-
如果你想在第一次渲染之前进行 AJAX 调用 - 你应该使用
beforeMount钩子。如果您还想捕获所有后续重新渲染,那么您还应该使用beforeUpdate钩子。 -
两个钩子都试过了,都没有得到数据。
-
当 AJAX 调用完成时你会得到数据——但那时 Vue 可能已经渲染了组件,所以数据到达会触发重新渲染。
-
我认为你的应用程序没有重新渲染的问题是你在你的getter中检索整个
state......我知道在较新版本的Vue和Vuex中,反应式更好,它可以识别数组或子属性的变化。但是我建议您做的第一件事是:在您的状态中创建一个名为 weather 的属性,并在您的突变中,在检索数据时为该属性设置一个全新的对象,然后在您的 getter 中您只返回 @ 987654326@. -
感谢您的建议。但这很可能不是因为返回整个州。我什至尝试在 getter 和突变中只返回一个属性。此外,问题不在于重新渲染,数据甚至没有在第一页加载时加载到计算属性中。奇怪的是,我可以在控制台中看到该操作已调度,但由于某种原因,计算的属性没有接收到数据。但是当页面重新加载时,他们就会得到数据。