ee-vuex
v2.5.0
Published
More convenient global status manager than Vuex and Pinia
Downloads
523
Readme
ee-vuex
Intuitive, type safe and flexible Store for Vue.
"ee" represents Encapsulated and Easy, making developers' code more concise.
- 💡 Intuitive
- 🔑 Type Safe
- 🔌 Extensible
- 🏗 Modular by design
- 📦 Extremely light
👉 Demo with Vue 3 on StackBlitz
Feature
- More clear and concise definition: A state is an object, rather than being defined in multiple objects such as state and getters
- More simple and convenient to use: No need for methods such as mapGetters and mapState, no need for methods such as commit and dispatch, just call and assign states directly
- v-model: You can use global state directly with the v-model
- cache: Computed cache can be used to improve get efficiency when attribute values remain unchanged
Not only that, but there are more convenient and powerful aspects of ee-vuex. Please see Definition Core in detail
You can first compare the core concepts of Vuex with ee-vuex through the table below, or directly refer to Usage to list the usage of ee-vuex
||vuex|ee-vuex(computed)| |-|-|-| state|- Definitionstate: { key: value,}- Invoke$store.state.key|- Definitionkey: value- Invoke$store.key| getters|- Definitiongetters: { key(state) { return state.key }}- Invoke$store.getters.key|- Definitionkey() {}- Invoke$store.key| mutations|- Definitionmutations: { key(state, value) { state.key = value 2 }}- Invoke$store.commit("key", value)|- Definitionkey(value) { return value 2 }- Invoke$store.key = value| actions|- Definitionactions: { async key({commit}, value) { await new Promise(r => { setTimeout(() => r(), 1000) }) commit("key", value) }}- Invoke$store.dispatch("key", value)|- Definitionasync key(value) { return await new Promise(r => { setTimeout(() => r(value) , 1000) })}- Invoke$store.key = value| module|- Definitionconst moduleA = { state: { key: 'a' }}const moduleB = { state: { key: 'b' }}createStore({ modules: { a: moduleA, b: moduleB }})- Invoke$store.state.a.key$store.state.b.key|- DefinitioncreateStore({ key: 'a'}, '$a')createStore({ key: 'b'}, '$b')- Invoke$a.key$b.key| v-model|- DefinitioncreateStore({ state: { key: undefined }, mutations: { key(state, value) { state.key = value } }})- Invoke <input type="text" v-model="key" />...computed: { key: { get () { return this.$store.state.key }, set (value) { this.$store.commit('key', value) } }}|- DefinitioncreateStore({ key: undefined}, '$store')- Invoke <input type="text" v-model="$store.key" />...| localStorage|- DefinitioncreateStore({ state: { key: JSON.parse( localStorage.getItem('key')) }, mutations: { key(state, value) { state.key = value localStorage.setItem('key', JSON.stringify(value)) } }})|- DefinitioncreateStore({ key: { p: 1, } })|
Installation
# or pnpm or yarn
npm install ee-vuex
Usage
1. Basic Usage
Here is an example of using counters that are both available in Vuex and Pinia
// stores/counter.js
import { createStore } from 'ee-vuex'
export default createStore({
count: 1,
}, "$ee")
Define the store and use it in a component
// Import Store
// import $ee from '@/stores/counter'
// or
// import eeVuex from 'ee-vuex'
// const { $ee } = eeVuex // or const $ee = eeVuex.$ee
// or(Recommended)
const { $ee } = require('ee-vuex').default
export default {
setup() {
console.log($ee.count) // -> 1
$ee.count++
console.log($ee.count) // -> 2
// Return the store instance to use it in the template
return { $ee }
},
}
The Options API makes it easier to use the ee-vuex. You can globally register the store with the Vue instance at the entrance, so there is no need to repeatedly import the store for each component
// main.js
import { createApp } from 'vue'
import $ee from './stores/counter.js'
createApp({ /* Component */ })
// Global Registration Store
.use($ee)
.mount('#app')
Using globally registered stores in components defined by Options APIs
export default {
mounted() {
console.log(this.$ee);
}
}
Using global states in templates is also very simple
<template>
<div @click="$ee.count++">{{ $ee.count }}</div>
<input v-model="$ee.count" />
</template>
2. Advanced Usage
The second parameter of createStore can give the store created by ee-vuex more advanced usage
import { createStore } from 'ee-vuex'
// It can directly represent the store name as a string
export default createStore({}, "$ee")
// Or it can be an object that provides a more detailed definition
// of the special usage of the store
export default createStore({},
{
name: "$ee",
this: undefined,
set(key, value, store) { },
})
- name: The name of the store
- this: When calling the get/set/default method, this points to the store instance by default
- set: Callback after assigning a property
Please refer to the following examples for the specific usage of these configurations
2.1 Multiple Stores
- Store names can distinguish instances of stores
- All named stores can be registered at once using the default object returned by ee-vuex
import { createApp } from 'vue'
import ee, { createStore } from 'ee-vuex'
const vue = createApp({ /* Component */ });
// Create and register stores one by one
// vue.use(createStore({}, "$store1"))
// vue.use(createStore({}, "$store2"))
// vue.use(createStore({}, "$store3"))
// Create stores one by one
// Register all named stores at once (recommended)
createStore({}, "$store1")
createStore({}, "$store2")
createStore({}, "$store3")
vue.use(ee);
// Non named store, you need to save the store instance yourself
// Calling vue.use(store) has no effect
const store = createStore({});
In the Vue component, the instance of the store can be obtained through the name
<template>
<div>{{ $store1 }}</div>
<div>{{ $store2 }}</div>
<div>{{ $store3 }}</div>
</template>
2.2 data Store
It is recommended to skip this chapter first and read through Define Core to understand the convenience of defining states in ee-vuex before returning here
Please ensure that you have understood the following points before reading this chapter
- Understand the Options API
- Understand the Basic Usage of ee-vuex
- ee-vuex can create Multiple Stores through createStore
- ee-vuex uses Object-Oriented Design Approach to Define Store States
Local stores are created in Vue components to replace data, computed, and watch
import { createStore } from 'ee-vuex'
export default {
data() {
// Same usage as global stores
// example: this.$ee.count
return {
$ee: createStore({
count: {
default: this.modelValue,
set(value) {
this.$emit("update:modelValue", value);
}
}
},
{
// Local stores do not require setting a store name
// Local stores this should point to the instance of Vue component
this: this
})
}
// No need for a store instance
// the store instance is just the component instance
// example: this.count, Compared to the above usage methods
// the $ee store instance is no longer needed
// return createStore({ ... }, { ... })
},
props: ['modelValue'],
watch: {
// The ee-vuex can only replace data and computed
// and a watch is still required for changes in props
modelValue(value) {
this.$ee.count = value;
}
}
}
2.3 props Store
The props in Vue are unidirectional data streams, and when using the v-model, it can also be considered bidirectional. In the combination API notation of Vue 3.4+, defineModel has been added to facilitate the definition and use of props properties. The props store of ee-vuex is equivalent to an option based solution for defineModel, and the solution of ee-vuex was developed earlier and more convenient than defineModel. For such props, they can be assigned values both externally and internally, and the assignment effect should be consistent
Core method: injectStore
// hello-ee-vuex.vue
import { injectStore } from 'ee-vuex'
// Export Component Call injectStore
export default injectStore({
props: {
count: {
// There are two ways to define props: ee-vuex and original Vue's props
// ee-vuex: get, set, p, init, default
// vue: type, required, validator, default
type: Number,
// Both default methods are available
// only the vue takes effect
default: 0,
// Including 'get', so count is the prop of ee-vuex
get() {},
},
// This is the original definition of props
// which does not include the features of ee-vuex
origin: [String, Number],
},
})
Props can be defined using either the original definition of props or the Definition Method in ee-vuex
injectStore
has more comprehensive type prompts than defineComponent
, so it is not recommended to mix two definition methods in one state
The ee-vuex form of props is read-write bidirectional, and the usage method is as follows
- Component internal: props become writable and can be directly assigned values
<!-- The template can be directly assigned values -->
<template>
<p @click="count++">{{ count }}</p>
<input v-model="count" />
</template>
...
// JavaScript can also directly assign values
mounted() {
this.count = 5;
}
- Component external: used as before
<template>
<hello-ee-vuex v-model="myCount" @click="myCount++" />
<p>{{ myCount }}</p>
</template>
<script>
export default {
data() {
return {
myCount: 5,
}
}
}
</script>
At this point, the internal component's p and input, and the external component's p will synchronously display the same data. And when both internal and external components click on the p tag, both components can see data increment
- extends & mixins: When a component is used for extends or mixins, you only want to modify the default value of props, which can be assigned in the
beforeMount
lifecycle
// child.vue
import parent from './hello-ee-vuex.vue'
export default {
extends: parent,
beforeMount() {
// If there is no external value assigned to props
// set the default value to 1
if (this.$props.count === undefined)
this.count = 1;
}
}
2.4 set
Set can record the assignment operations of all store states in the log
import { createStore } from 'ee-vuex'
export default createStore({
count: 0,
name: 'Hello World',
}, {
set(key, value, store) {
// count -> 0
// name -> Hello World
console.log(key, " -> ", value);
}
})
3. Type Inference
When creating a store, it is recommended to use a .ts file. Only a few simple lines of code are added, and there will be code prompts when calling the repository in the component
// Change the file suffix to .ts:stores/counter.ts
import { createStore } from 'ee-vuex'
const store = createStore({ count: 1, }, "$ee")
// Adding these few lines of code will provide code prompts
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
// Pay attention to the consistency
// between variable names and store names
$ee: typeof store,
}
}
export default store;
The instance returned by creating a repository in JavaScript also has code prompts, and the field type depends on the default or JSdoc defined type
import { createStore } from 'ee-vuex'
const store = createStore({
// num is of type number
num: 1,
// str is of type string
str: '',
// arr is of type any[]
arr: () => [],
// arr2 is of type {a:number, b:string}[]
/** @type { function():{a:number, b:string}[] } */
arr2: () => [],
// obj is of type number
obj: {
default: 5
}
})
Async State
The default value, get, and set of the store state can all generate results asynchronously. Before asynchronous completion, the state will maintain its previous value
The asynchronous result of obtaining the state is very useful for displaying loading animations, such as obtaining a list of all languages from the backend
const store = createStore({
languages: () => new Promise(resolve => {
setTimeout(() => {
// Here, we use latency to simulate API latency
resolve(['zh', 'en', 'jp'])
}, 1000)
})
}, 'store')
Template displays language list, but shows loading animation before loading is complete
<template>
<div v-if="store.getAsync('languages').async">Loading...</div>
<ul v-else>
<li v-for="item in store.languages">{{ item }}</li>
</ul>
</template>
The core method for obtaining asynchronous state is store.getAsync
, which returns an object containing two values
async: boolean
Is it asynchronouspromise: Promise<T> | T
Asynchronous process, if there is no asynchrony, it will obtain the current value
The component instance created by injectStore also has the getAsync
function
Definition Core
In the store definition of ee vuex, a state is an object that contains the following 4 fields
- default: State's (Default Value)
- p: Automatically set and restore state values using localStorage(Persistence)
- get: Triggered when obtaining state(Get Function)
- set: Triggered when assigning a status(Set Function)
And when you only want to customize one of these fields, there will also be a corresponding concise definition method.
For the benefits of defining states in this way, please refer to Advantages of ee-vuex
The following example code is written in the Create Store reference Basic Usage
import { createStore } from 'ee-vuex'
createStore({
// The following example code should be written in this object
})
1. Default Value
The common default values are easy to understand, just look at the following code examples.
The default value of ee-vuex is very useful for asynchronous caching enumerated data.
For example, our page supports multiple languages, and the type of language needs to be asynchronously obtained from the backend through the API. The data is an array.
Before asynchronously obtaining data, we want the value of the state to be an empty array, so that the page can be directly used in a v-for loop without tedious v-if judgment.
In the above example, the status default value should have the following characteristics:
- There are 2 default values
- Initially, the default value is an empty array
- Replace default values after api asynchronously obtains data
The default value of ee-vuex has the following characteristics to meet the above requirements
- Support Array: Direct default values
- Supports Asynchronous: The default value can be an asynchronous Promise or a function that returns Promise, allowing access to the API to obtain the value
- Support Lazy Loading: First get will Trigger once an assignment of the default value, which can save performance and memory
For specific implementation, please see the following example of multiple default values
- General Definition: Field default
key: {
default: undefined,
}
- Concise Definition: Write values directly
key: undefined
The default value supports a wide range of types. The following example codes provide examples one by one
- Normal value: directly assign a value
key: 1
key: true
key: "ee-vuex"
key: new Date()
- Function: You can use methods to return default values, and support asynchronous methods and Promises. Note: Please use arrow functions for concise definitions, otherwise they will be considered as get function or set function.
// Direct return value: ee-vuex
key: () => "ee-vuex"
// Asynchronous Promise return value:
// undefined 2 seconds ago, ee-vuex 2 seconds later
key: () => new Promise(resolve => {
setTimeout(() => {
resolve("ee-vuex")
}, 2000)
})
// The async method return value:
// undefined 2 seconds ago, 10000 after 2 seconds
key: async () => {
// Get values asynchronously
const value = await new Promise(
resolve => {
setTimeout(() => {
resolve(100)
}, 2000)
})
// You can customize values
return value * value;
}
// NG: Will be considered a get function, with the default value undefined
key: function() { return 5 }
- Object: When using a simple definition, it is necessary to distinguish it from the object defined by the state. It cannot contain any of p, init, default, get, or set
// OK: Default value is object
key: {
name: 'ee-vuex',
isCool: true,
}
// NG: The default value is true
key: {
name: 'ee-vuex',
// Contains default
default: true,
}
// When you want to include objects with p, default, get, and set fields
// you can use Function or do not use concise definitions.
// OK: Use Function to return a value. The default value is the object
key: () => {
return {
name: 'ee-vuex',
default: true,
}
}
// OK: Use general definitions, with the default value being the object
key: {
default: {
name: 'ee-vuex',
default: true,
}
}
- Multiple default values: init and default
// 2 seconds ago 0, 2 seconds later 2
key: {
// Synchronous, function not supported
init: 0,
// Asynchronous, can be a function that automatically calls
// to read the return value
default: async () => {
return await new Promise(resolve => {
setTimeout(() => {
// Assign value after 2 seconds
resolve(2);
}, 2000)
})
}
}
2. Persistent
The value of the store state is stored in memory, and when we refresh the page, the value of the status will be cleared.
Persistence is when we want to refresh a page, the value of the state remains the value of the last run. It can be used in scenarios such as login tokens, user selected languages, and so on.
Generally, we will save the state of the store to localStorage, read it out during initialization, and write it in during set.
Persistence is a very common function for stores, so ee-vuex adds simple configurations to assist in implementation without having to implement persistence repeatedly.
Using persistence requires attention:
- Priority is given to reading the value of localStorage. If there is a value, Default Value will be ignored
- The saved key is the name of the state, and modification is temporarily not supported. Please note that it does not have the same name as other localStorage content in your project
- General Definition: Field p. 'p' is an acronym for Persistent, which is used because it is too difficult to remember
token: { p: 1 }
- Concise Definition: Directly assign a value to localStorage
token: localStorage
- Custom Implementation: It can also be easily implemented using Default Value and Set Function
token: {
default: () => JSON.parse(localStorage.getItem('token')),
set(value) {
if (value)
localStorage.setItem('token', JSON.stringify(value));
else
localStorage.removeItem(key);
}
}
3. Get Function
Like the Vue component computed get, it is a function. The ee-vuex get function supports asynchronous return of Promise.
When Promise is returned, and Promise completes and returns a non null value, set will be called to set the return value to the status.
This is useful when it is necessary to automatically and asynchronously obtain values during get, such as the Login example in actual combat.
The difference from the default value is that the default value is only set once and does not change. However, in the case where the login example allows logout, the next time you log in to another account, you may need to retrieve the value asynchronously. At this time, it should be more convenient to use asynchronous get.
- General Definition: Field get. The first parameter obtains the current status value. Note that computed will refresh the cache of the get when the value is updated, and using this.key in the get function will still obtain the cached value
key: {
get(value) {
// this.key can only obtain cached values
console.log("value", value, "oldvalue", this.key)
}
}
- Concise Definition: Note that the number of parameters should not be confused with Set Function, and that arrow functions should not be used to prevent confusion with Default Value
key() {}
// OK: Parameter required, please write two more useless parameters
key(value, x, y) {}
// OK: Can be defined by function
key: function() {}
// NG: The arrow function cannot be used and will be considered the default value
key: () => {}
- Asynchronous: The return value of an asynchronous promise is directly set to the state, causing a state change. The computed cache becomes invalid. If it is a template reference state, the state will be obtained again. Therefore, it is important to use judgment to prevent multiple asynchronous values from causing a dead cycle
// When obtaining a key after setting the token,
// an undefined value is returned 2 seconds ago,
// and the same value as the token is returned 2 seconds later
token: undefined,
async key(value, x, y) {
// Pay attention to adding judgment to assign values
// when there is no value,
// to prevent multiple asynchronous values
if (this.token && !value) {
return await new Promise(r => {
setTimeout(() => {
r(this.token)
}, 2000)
})
}
}
4. Set Function
Like the Vue component computed set, it is a function. Similarly, the ee-vuex set function also supports asynchronism, like the Actions of vuex and pinia.
It should be noted that:
- Set will not be called when the same value is set
// Define state
key: {
default: 1,
set(value) {
console.log("new value", value)
}
}
// Vue Component
mounted() {
// 'new value 1' will not be output on the console
this.$store.key = 1;
}
- When the status has Default Value, the default value is assigned when getting. If you manually set the value before getting, the default value will be ignored during get to ensure that the value you set is not overwritten by the default value. However, if your default value contains asynchronism and is already executing, then set cannot stop the executing asynchronous operation, which may cause the asynchronous default value to overwrite your set value. Please try not to design the state in this way.
// Define state
key: [1, () => new Promise(r => {
setTimeout(() => {
r(3)
}, 2000)
})]
// Vue Component
// Example 1: set before get
mounted() {
// Set first
// the value of key is 2, and the default value will no longer be valid
this.$store.key = 2;
console.log(this.$store.key); // output 2
// The default value is no longer valid,
// and the subsequent key values are consistently 2
setTimeout(() => {
console.log(this.$store.key); // output 2
}, 3000)
}
// Example 2: get before set
mounted() {
// Get first
// the default value of 1 has been set, and Promise is already being executed
console.log(this.$store.key); // output 1
// Set the key to 2
this.$store.key = 2;
console.log(this.$store.key); // output 2
// Promise is already executing, and set cannot be interrupted.
// After 2 seconds, the key will change to the asynchronous default value of 3
setTimeout(() => {
console.log(this.$store.key); // output 3
}, 3000)
}
- When calling the set function, the value has not been actually assigned to the state, so calling get within the set function cannot obtain the latest value. If you need to get the value of the state itself in the set function, you can use setTimeout to delay the call
key(value) {
// If the value is 1, 'value 1 oldvalue undefined' will be output
console.log("value", value, "oldvalue", this.key)
// output '$store.key: undefined'
api();
setTimeout(() => {
// output '$store.key: 1'
api();
})
// After calling set, output '$store.key: 1'
set(value);
api();
}
// The API method prints the value of the store state key
const api = () => {
console.log("$store.key:", $store.key)
}
- General Definition: Field set. The parameter is the currently set value
key: {
set(value) {}
}
- Concise Definition: Note that only one parameter is considered a set function, even if it is an arrow function
key(value) {}
// Can be defined by function
key: function(value) {}
// Can be defined by arrow function
key: (value) => {}
- Return Value: When calling set, the value has not been actually set to the state. You can determine the final state value by returning a non null value
// For example, the value is 2, and the final key value is 4
key(value) {
return value * value;
}
- Asynchronous: Asynchronous is the same as the Get Function. Set asynchrony can be used, for example, when synchronous settings are required to the server. Using catch can prevent this assignment
// If Promise is successful, the local and server values will remain consistent.
// If Promise is incorrect, this assignment will fail.
async lauguage(value) {
await api.setLanguage(value);
console.log("Successfully synchronized value with the server")
},
Complete Example
import { createStore } from 'ee-vuex'
import { api } from './your-api-js'
createStore({
// (Complete Example)The token of the logged in user
token: {
p: 1,
default: "",
get(value) { return 'bearer ' + value; },
set(value) {
if (!value)
this.user = undefined;
}
},
// (get example)Login user information:
// Obtain from the background when there is no data,
// and return an empty object before obtaining
user(value, x) {
if (!value && this.token)
return api.getUser();
return value || {};
},
// (default value example)All languages: Get all languages from the background
languages: [[], () => api.getLanguages()],
// (set example)User setting language: default en, and can be persistent
language: {
default: "en",
p: 1,
async set(value) {
// Notify the server user to choose the language to use
await api.setLanguage(value);
console.log("Successfully synchronized value with the server")
}
},
})
More Example
Login
- After the user logs in, they have a token that needs to be persisted, and the get of the token needs to be prefixed with 'bearer '
- Use token to obtain user information from the background interface when calling user for the first time
- The token and user will be cleared after the user logs out
- vuex
import { createStore } from 'vuex'
const store = createStore({
state: {
// Restore the persistent token as the default value
token: localStorage.getItem('token'),
user: undefined,
},
getters:{
token(state) {
return 'bearer ' + state.token;
},
user(state) {
if (!state.user && state.token) {
// Obtain user information through the API, using setTimeout instead
// Problem 1. If the template references getters.user in multiple places,
// the asynchronous request will be triggered multiple times
// before the asynchronous request ends and the user is obtained
setTimeout(() => {
// Problem 2. Cannot use this in getters
// to point to the current instance of the store
store.commit('setUser', { name: 'UserName' })
}, 5000)
}
// Let the API return an empty object
// before obtaining user information to prevent empty references
return state.user || {};
},
},
mutations: {
setToken(state, token) {
state.token = token;
if (token) {
// Persisting the token
localStorage.setItem('token', token)
} else {
// Clear the token and also clear the user information together
localStorage.removeItem('token');
this.commit('setUser', undefined);
}
},
setUser(state, user){
state.user = user;
// Problem 3. Regardless of clearing token or user,
// the other state should be cleared together,
// but clearing each other can lead to a dead cycle
if (!user)
this.commit('setToken', undefined);
},
},
})
export default store;
Problems with vuex
- Get asynchronously obtains data and sets it. When getting multiple times, obtaining data asynchronously multiple times can cause performance losses
- When it is necessary to set other states under get, it is inconvenient to call the scope without this
- Setting the same value will also execute set, and setting back and forth will cause a dead loop
- A state needs to be defined three times (state, getters, mutations), and the code is not concise
- ee-vuex
import { createStore } from 'ee-vuex'
export default createStore({
token: {
p: true,
get(value) {
return 'bearer ' + value;
},
set(value) {
// Clear the token and also clear the user information together
if (!value)
this.user = undefined;
}
},
user: {
get(value) {
if (!value) {
// Obtain user information through the API, using setTimeout instead
// Comparison 1. If the template references a user in multiple places,
// only one asynchronous request will be triggered
// Because the user value has not changed,
// the computed feature returns the cached value of the user
setTimeout(() => {
// Comparison 2. This can also be used in get
// to point to the current instance of the store
this.user = { name: 'UserName' };
}, 5000)
}
},
set(value) {
if (!value) {
// Comparison 3. Regardless of clearing token or user,
// the other state should be cleared together,
// and mutual clearing will not lead to a dead cycle
// Because of the same value as set,
// the set method will not be triggered,
// similar to the Vue component's watch
this.token = undefined;
// Let the API return an empty object
// before obtaining user information to prevent empty references
return {};
}
}
},
})
The code indicates a comparison between ee-vuex
- Get asynchronously obtains data and sets it. When getting multiple times, the cache will be returned to improve line performance
- When other states need to be set under get, the scope can be pointed to itself using this
- Setting the same value does not execute set, and round-trip sets do not cause a dead loop
- A state only defines one object, and the code is concise
BUG
- For example, the following example simulates a radio component
import { injectStore } from 'ee-vuex'
export default injectStore({
name: "radio",
props: {
// Value when selected
value: { default: true },
// ee-vuex's props
modelValue: false,
},
computed: {
// is checked
checked: {
get() {
return this.modelValue == this.value;
},
set(value) {
if (value)
this.modelValue = this.value;
else
this.modelValue = undefined;
}
}
},
watch: {
// Mainly when modifying the value, it may cause checked changes
// It is necessary to synchronize the values of modelValue and value
checked(value) {
this.checked = value;
}
}
})
- When creating a component, the execution order of the code is
watch -> checked.get -> props.modelValue -> beforeMount
The injectStore of ee-vuex injects the read and write properties of props into the data during beforeMount
That is to say, the modelValue referenced by checked.get should be data.modelValue instead of props.modelValue
Resulting in no response from checked.get and data.modelValue
- Solution: Instead of using watch and computed, use ee-vuex instead
import { injectStore } from 'ee-vuex'
export default injectStore({
name: "radio",
props: {
value: { default: true },
modelValue: false,
// use ee-vuex instead
checked: {
get() {
return this.modelValue == this.value;
},
set(value) {
if (value)
this.modelValue = this.value;
else
this.modelValue = undefined;
}
}
},
})