Child 在 boolean 属性更改时不更新
Child is not updated when boolean prop is changed
我有以下组件:
Parent:
<template>
<Child path="instance.json"
v-bind:authenticated="authenticated"
v-bind:authenticator="authenticator"
/>
</template>
<script>
import { getAuthenticator } from '../auth';
export default {
data() {
return {
authenticated: false,
authenticator: null
};
},
beforeMount: async function () {
this.authenticator = getAuthenticator()
this.checkAccess();
},
methods: {
checkAccess() {
this.authenticated = this.authenticator.isAuthenticated();
},
async login() {
this.checkAccess();
await this.authenticator.signIn();
this.checkAccess();
}
}
};
</script>
Child:
<template>
<div id="swagger-ui"></div>
</template>
<script>
import swagger from "swagger-ui-dist";
import "swagger-ui-dist/swagger-ui.css";
export default {
props: ["path", "authenticated", "authenticator"],
mounted: async function() {
if (this.authenticated) {
let token = (await this.authenticator.getToken()).accessToken;
const ui = swagger.SwaggerUIBundle({
url: this.path,
dom_id: "#swagger-ui",
onComplete: function() {
ui.preauthorizeApiKey("token", token);
}
});
} else {
const ui = swagger.SwaggerUIBundle({
url: this.path,
dom_id: "#swagger-ui"
});
}
}
};
</script>
在parent组件中,调用login
方法时,authenticated
变量变为true
。由于 authenticated
作为道具传递给 Child 组件,我希望 Child 在 authenticated
更改时刷新。但是,Child 不会刷新。
我认为问题可能是因为我根本没有在 child 的模板中使用 authenticated
。相反,我只在 mounted
挂钩中使用它。就我而言,模板中的 authenticated
没用。
我尝试了两种解决方案:
- 在 Parent 的
login
方法中调用 this.$forceUpdate()
- 根本不起作用(没有任何改变)
- 将
:key
添加到 Child,并在每次调用 login
时更改密钥 - 这可行,但是,它有点 hacky。我想了解如何正确地做到这一点。
你没有在模板中使用它很好,问题是你只在 child 的 mounted
挂钩中检查 authenticated
,它只运行一次(当时是false
)。
您应该使用 watch
来跟踪对 authenticated
属性的更改,而不是 mounted
:
watch: {
authenticated: {
handler(newValue, oldValue) {
this.setUi();
},
immediate: true // Run the watch when `authenticated` is first set, too
}
}
每次 authenticated
变化时都会调用一个 setUi
方法:
methods: {
async setUi() {
if (this.authenticated) {
let token = (await this.authenticator.getToken()).accessToken;
const ui = swagger.SwaggerUIBundle({
url: this.path,
dom_id: "#swagger-ui",
onComplete: function() {
ui.preauthorizeApiKey("token", token);
}
});
} else {
const ui = swagger.SwaggerUIBundle({
url: this.path,
dom_id: "#swagger-ui"
});
}
}
}
你需要的是使用观察者。
实际上,您的代码只有 运行 一次(当安装 de 组件时),而不是在每次 prop 更改时。
<template>
<div id="swagger-ui"></div>
</template>
<script>
import swagger from 'swagger-ui-dist';
import 'swagger-ui-dist/swagger-ui.css';
export default {
props: {
path: {
type: String,
default: '',
},
authenticated: {
type: Boolean,
default: false,
},
authenticator: {
type: Object,
default: () => {},
},
},
watch: {
async authenticated(newValue) {
await this.updateSwagger(newValue);
},
},
async mounted() {
await this.updateSwagger(this.authenticated);
}
methods: {
async updateSwagger(authenticated) {
if (authenticated) {
const token = (await this.authenticator.getToken()).accessToken;
const ui = swagger.SwaggerUIBundle({
url: this.path,
dom_id: '#swagger-ui',
onComplete: function () {
ui.preauthorizeApiKey('token', token);
},
});
} else {
const ui = swagger.SwaggerUIBundle({
url: this.path,
dom_id: '#swagger-ui',
});
}
},
},
};
</script>
我有以下组件:
Parent:
<template>
<Child path="instance.json"
v-bind:authenticated="authenticated"
v-bind:authenticator="authenticator"
/>
</template>
<script>
import { getAuthenticator } from '../auth';
export default {
data() {
return {
authenticated: false,
authenticator: null
};
},
beforeMount: async function () {
this.authenticator = getAuthenticator()
this.checkAccess();
},
methods: {
checkAccess() {
this.authenticated = this.authenticator.isAuthenticated();
},
async login() {
this.checkAccess();
await this.authenticator.signIn();
this.checkAccess();
}
}
};
</script>
Child:
<template>
<div id="swagger-ui"></div>
</template>
<script>
import swagger from "swagger-ui-dist";
import "swagger-ui-dist/swagger-ui.css";
export default {
props: ["path", "authenticated", "authenticator"],
mounted: async function() {
if (this.authenticated) {
let token = (await this.authenticator.getToken()).accessToken;
const ui = swagger.SwaggerUIBundle({
url: this.path,
dom_id: "#swagger-ui",
onComplete: function() {
ui.preauthorizeApiKey("token", token);
}
});
} else {
const ui = swagger.SwaggerUIBundle({
url: this.path,
dom_id: "#swagger-ui"
});
}
}
};
</script>
在parent组件中,调用login
方法时,authenticated
变量变为true
。由于 authenticated
作为道具传递给 Child 组件,我希望 Child 在 authenticated
更改时刷新。但是,Child 不会刷新。
我认为问题可能是因为我根本没有在 child 的模板中使用 authenticated
。相反,我只在 mounted
挂钩中使用它。就我而言,模板中的 authenticated
没用。
我尝试了两种解决方案:
- 在 Parent 的
login
方法中调用this.$forceUpdate()
- 根本不起作用(没有任何改变) - 将
:key
添加到 Child,并在每次调用login
时更改密钥 - 这可行,但是,它有点 hacky。我想了解如何正确地做到这一点。
你没有在模板中使用它很好,问题是你只在 child 的 mounted
挂钩中检查 authenticated
,它只运行一次(当时是false
)。
您应该使用 watch
来跟踪对 authenticated
属性的更改,而不是 mounted
:
watch: {
authenticated: {
handler(newValue, oldValue) {
this.setUi();
},
immediate: true // Run the watch when `authenticated` is first set, too
}
}
每次 authenticated
变化时都会调用一个 setUi
方法:
methods: {
async setUi() {
if (this.authenticated) {
let token = (await this.authenticator.getToken()).accessToken;
const ui = swagger.SwaggerUIBundle({
url: this.path,
dom_id: "#swagger-ui",
onComplete: function() {
ui.preauthorizeApiKey("token", token);
}
});
} else {
const ui = swagger.SwaggerUIBundle({
url: this.path,
dom_id: "#swagger-ui"
});
}
}
}
你需要的是使用观察者。 实际上,您的代码只有 运行 一次(当安装 de 组件时),而不是在每次 prop 更改时。
<template>
<div id="swagger-ui"></div>
</template>
<script>
import swagger from 'swagger-ui-dist';
import 'swagger-ui-dist/swagger-ui.css';
export default {
props: {
path: {
type: String,
default: '',
},
authenticated: {
type: Boolean,
default: false,
},
authenticator: {
type: Object,
default: () => {},
},
},
watch: {
async authenticated(newValue) {
await this.updateSwagger(newValue);
},
},
async mounted() {
await this.updateSwagger(this.authenticated);
}
methods: {
async updateSwagger(authenticated) {
if (authenticated) {
const token = (await this.authenticator.getToken()).accessToken;
const ui = swagger.SwaggerUIBundle({
url: this.path,
dom_id: '#swagger-ui',
onComplete: function () {
ui.preauthorizeApiKey('token', token);
},
});
} else {
const ui = swagger.SwaggerUIBundle({
url: this.path,
dom_id: '#swagger-ui',
});
}
},
},
};
</script>