vuex-aspect persisted example
by frissdiegurke
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Persisted vuex-aspect example</title>
<script type="text/javascript" src="https://unpkg.com/vuex"></script>
<script type="text/javascript" src="https://unpkg.com/shvl/dist/shvl.umd.js"></script>
<script type="text/javascript" src="https://unpkg.com/deepmerge/dist/umd.js"></script>
<script type="text/javascript" src="https://unpkg.com/vuex-persistedstate/dist/vuex-persistedstate.umd.js"></script>
<script type="text/javascript" src="https://unpkg.com/vuex-aspect/dist/vuex-aspect.umd.js"></script>
</head>
<body>
<div id="app">
<h2>Persisted Vuex Aspect Example</h2>
<p>
This example persists the <code>userId</code> and <code>user</code> to `sessionStorage` using vuex-persistedstate.
A server query is simulated by a random timeout between 0s and 6s. UserIDs <code>(x+2)%4 = 0</code> result in errors.
</p>
<div class="button-group">
<button @click="incrementUser">Next UserID</button>
<button @click="toggleConsumption">{{consume ? "Unmount consumer component" : "Mount consumer component"}}</button>
</div>
<table>
<tbody>
<tr>
<td><pre><code>userId</code></pre></td>
<td><pre><code>{{userId}}</code></pre></td>
</tr>
<tr>
<td><pre><code>user$loading</code></pre></td>
<td><pre><code>{{user$loading}}</code></pre></td>
</tr>
<tr>
<td><pre><code>user$error</code></pre></td>
<td><pre><code>{{user$error || "undefined"}}</code></pre></td>
</tr>
<tr>
<td><pre><code>user</code></pre></td>
<td><pre><code>{{user || "undefined"}}</code></pre></td>
</tr>
<tr>
<td><pre><code>consumer</code></pre></td>
<td><consumer v-if="consume"></consumer></td>
</tr>
</tbody>
</table>
</div>
<script type="text/javascript" src="./script.js"></script>
</body>
</html>
CSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
p {
font-size: small;
font-style: italic;
}
p code {
font-size: medium;
}
.button-group {
display: flex;
margin: 1em 0;
}
.button-group > button {
flex-grow: 1;
flex-basis: 50%;
margin: 0 0.5em;
}
table {
width: 100%;
}
tr {
border-bottom: 1px solid #e1e1e1;
}
tr:last-child {
border-bottom: none;
}
td {
width: 50%;
padding: 0.2em 1em;
}
pre {
background: #005fa533;
border: 1px solid #005fa533;
padding: 0.1em 0.2em;
margin: 0.1em 0.2em;
}
Vue
// aspect definition
const myUserAspect = new VuexAspect.Aspect({
variables({state}) { return {id: state.userId}; },
resolve(variables) { return fetchUser(variables); },
});
// consumer component
const consumer = Vue.component("consumer", {
mixins: [myUserAspect.mixin],
template: "<pre><code>nom nom nom...</code></pre>",
});
const persist = createPersistedState({
storage: sessionStorage,
paths: ["userId", "user"],
});
// main component
new Vue({
el: "#app",
components: {consumer},
methods: Vuex.mapMutations(["toggleConsumption", "incrementUser"]),
computed: Vuex.mapState(["consume", "userId", "user", "user$loading", "user$error"]),
store: new Vuex.Store({
plugins: [VuexAspect.install, persist],
state: {userId: 0, user: void 0, consume: false},
aspects: {user: myUserAspect},
mutations: {
toggleConsumption(state) { state.consume = !state.consume; },
incrementUser(state) { state.userId = state.userId + 1; },
},
}),
});
// simulated server fetch
function fetchUser(data) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if ((data.id + 2) % 4 === 0) { return reject({status: 404, message: "User #" + data.id + " does not exist."}); }
resolve({id: "user-" + data.id, name: "Jon Doe " + data.id});
}, Math.random() * 6000);
});
}