2

I'm trying to change a picture (daytime picture vs nighttime picture) dynamically when a person hits the light button. It works, but I have to refresh the page for the picture to show. Daytime and nighttime are basically just booleans of 'true' or 'false' for my theme variable.

I tried coding it this way:

useTheme.js:

import { ref, watchEffect } from 'vue';

export default function useTheme() {
    const theme = ref(JSON.parse(localStorage.getItem('theme') || 'false'));

    watchEffect(() => {
        localStorage.setItem('theme', String(theme.value));
    });

    return { theme };
}

App.vue:

const { theme } = useTheme(); // Access the shared state.

const toggleTheme = () => {
  theme.value = !theme.value;
  document.body.classList.toggle('dark-theme', theme.value);
  localStorage.setItem('theme', JSON.stringify(theme.value));
}

Home.vue (Where the problem resides):

  • Part of the HTML:
<img :src="banner" alt="Daytime Banner">
  • Calculating the daytime vs nighttime:
import DayTimeBanner from "@/assets/banner-city-daytime.png";
import NightTimeBanner from "@/assets/banner-city-nighttime.png";
...
const { theme } = useTheme(); // Access the same shared state.

const banner = computed(() => theme.value ? NightTimeBanner : DayTimeBanner);

Any clue on what might be going on? Changes to the theme background is reactive, but for the banner, I have to refresh the page for the image to pop up.

3
  • why are you setting the localStorage value in two places in two different ways? Commented Jul 9 at 9:22
  • @JaromandaX I have a button that toggles the theme change. And in the javascript file, I guess it also sets it there as well. Do you think this may be the cause?
    – Josh
    Commented Jul 9 at 10:08
  • I'm wondering why you do it in two different ways, that's all Commented Jul 9 at 10:27

3 Answers 3

1

The error is that in your useTheme.js file you are declaring the 'theme' state inside the function, so you are creating a local state each time you call the useTheme() function instead of a global one.

Change your code to this:

import { ref, watchEffect } from 'vue';

const theme = ref(JSON.parse(localStorage.getItem('theme') || 'false'));

watchEffect(() => {
    localStorage.setItem('theme', String(theme.value));
});

export default function() {
   return { theme };
}
2
  • 1
    Bingo. Thanks! I was wondering if it were stuck locally instead of globally.
    – Josh
    Commented Jul 9 at 21:28
  • 1
    No problem! Could you please upvote my answer as well? Thanks! Commented Jul 10 at 16:27
1

One of the reasons might be that useTheme does not return a reactive value. Try using ref or reactive

1
  • Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
    – Community Bot
    Commented Jul 10 at 13:40
0

Would be the easiest if you could apply a CSS instead of an asset to src.

Predefine the two classes for both of the banners ex:,

 background: lightblue url("/assets/banner-city-daytime.png") no-repeat fixed center;

I assume you know your way around CSS :)

Not the answer you're looking for? Browse other questions tagged or ask your own question.