问题
I have a chrome bug telling me Write operation failed: computed property "isDark" is readonly.
my mutation create a DarkMode key in the locastorage and I also create a store that checks if DarkMode exists in the localestorage
it works but if I refresh the page the mutation is inverted for example if in the localestorage darkMode is true if I click on the toggle the mutation is also a true then what should return false
My Page
<div id="home">
<div class="toggleTheme">
<ToggleBtnTheme
labelOn="Dark"
labelOff="Light"
v-model:value="isDark"
@input="mode"
/>
</div>
<div class="title">
<h1 :class="isDark ? 'dark' : 'light'">Lidian Manoha</h1>
</div>
</div>
</template>
<script>
import { mapMutations, mapGetters } from 'vuex';
import ToggleBtnTheme from '@/components/atoms/ToggleBtn/index';
export default {
name: 'Home',
components: {
ToggleBtnTheme
},
methods: {
...mapMutations('themeDarkMode', ['toggleDarkMode']),
mode() {
this.toggleDarkMode();
}
},
computed: {
...mapGetters('themeDarkMode', ['isDark'])
},
watch: {}
};
</script>
<style lang="scss" src="./style.scss" scoped></style>```
My Stores
``` return {
darkMode: true,
isDark: false
};
},
getters: DarkModeGetters,
mutations: DarkModeMutations,
action: DarkModeAction
};
```
My getters.js
```
export default {
isDark: state => state.isDark
};
```
My mutations.js
```
export default {
toggleDarkMode: state => {
state.isDark = !state.isDark;
console.log('mutation', state.isDark);
localStorage.setItem('DarkMode', JSON.stringify(state.isDark));
}
};```
And my ToggleBtn
```<template>
<div id="toggleBtn">
<div class="toggleBtnContainer">
<label class="label" v-if="label">{{ label }}</label>
<div class="containerToggle">
<input
v-bind="$attrs"
:id="`toggle${uuid}`"
:disabled="disabled"
type="checkbox"
:checked="value || checked"
@change="$emit('update:value', $event.target.checked)"
/>
<label
:for="`toggle${uuid}`"
v-html="value ? labelOn : labelOff"
@click="$emit('click', $event)"
></label>
</div>
</div>
</div>
</template>
<script>
import { uuid } from 'vue-uuid';
export default {
name: 'toggleBtn',
inheritAttrs: false,
props: {
value: { type: [Boolean, String, Number, Function], default: false },
checked: { type: Boolean, default: false },
labelOn: { type: String, default: 'off' },
labelOff: { type: String, default: 'on' },
label: { type: String, default: null },
disabled: { type: Boolean, default: false }
},
data() {
return {
uuid: uuid.v4()
};
}
};
</script>
<style lang="scss" src="./style.scss" scoped></style>```
回答1:
Thats probably because you missed a point. When you refresh the page...ie the app reloads... if you find that there is a data('Darkmode') available in the local storage then you need to set it through the mutation in the first place. By doing so what happens is when you refresh the page...if darkmode is already set to true then your vuex state('isDark') will also be set to true. Therefore when you click on that it will toggle as expected.
Its better to have two mutations to avoid confusions
My mutations.js
export default {
toggleDarkMode: state => {
state.isDark = !state.isDark;
console.log('mutation', state.isDark);
localStorage.setItem('DarkMode', JSON.stringify(state.isDark));
},
initializeDarkMode: (state, payload) => {
state.isDark = payload; // payload is actually the value that was stored in the local storage
}
};
When the app loads, just call the second mutation to initialize the state with the local storage value.
this.initializeDarkMode(DarkMode); // DarkMode contains the value fetched from local storage
Below I have modified the code to call the second mutation
<div id="home">
<div class="toggleTheme">
<ToggleBtnTheme
labelOn="Dark"
labelOff="Light"
v-model:value="isDarkMode" // ****************Changes added *****************
@input="mode"
/>
</div>
<div class="title">
<h1 :class="isDark ? 'dark' : 'light'">Lidian Manoha</h1>
</div>
</div>
</template>
<script>
import { mapMutations, mapGetters } from 'vuex';
import ToggleBtnTheme from '@/components/atoms/ToggleBtn/index';
export default {
name: 'Home',
components: {
ToggleBtnTheme
},
data() {
return {
isDarkMode: this.isDark,
},
watch: {
isDark(newVal) {
this.isDarkMode = newVal;
}
},
// ****************Changes added below *****************
mounted() {
const isDark = localStorage.getItem('DarkMode');
if(isDark && isDark === 'true') {
this.initializeDarkMode(true);
this.isDarkMode = true;
} else {
this.initializeDarkMode(false);
this.isDarkMode = false;
}
methods: {
...mapMutations('themeDarkMode', ['toggleDarkMode', 'initializeDarkMode']),
mode() {
this.toggleDarkMode();
}
},
computed: {
...mapGetters('themeDarkMode', ['isDark'])
},
watch: {}
};
</script>
<style lang="scss" src="./style.scss" scoped></style>
来源:https://stackoverflow.com/questions/65807129/darkmode-with-vuex-and-save-in-localstorage