Dev
Dev

Reputation: 1223

Vue.js 3.0 - Update component UI when store property value changes via composition API

I am writing a Vue.js app using Vue.js 3.0. I'm using this as a way to learn the composition API. One thing that is unclear to me is how to conditionally update my component UI when a store value is updated. To demonstrate my issue, I've created this fiddle. The code is detailed here:

JavaScript

const store = {
  state: reactive({
    result = null
  }),
  generateNewValue() {
    this.state.result = Math.floor(Math.random() * 10);
  }
};

const MyApp = {
  setup() {
    return {
    }
  }
}
const myApp = Vue.createApp(MyApp)

myApp.component("banner", 
  { 
    template: '<button @click="onGenerateClick">generate</button>',
    setup(props) {
      console.log('setting up...');
    },
    methods: {
      onGenerateClick() {
        store.generateNewValue();
      }
    }
  }
);

myApp.component("content", {
  template: '<div><span>Content</span><button @click="onGenerateClick">generate</button></div>',
  methods: {
    onGenerateClick() {
      store.generateNewValue();
    }
  }  
});

myApp.mount('#my-vue')

HTML

<div id="my-vue">
  <banner></banner>
  <hr />
  <content></content>
</div>

CSS

.even-banner {
  background-color:navy;
  color: #fff;
}

.even-content {
  background-color:blue;
  color: #fff;
}

.odd-banner {
  background-color:maroon;
  color:#fff;
}

.odd-content {
  background-color:red;
  color:#fff;
}

When I click the "generate" button, a random number is generated. If that number is even, I want to set the content div to use the even CSS class. If it is an odd number, I want to apply the odd CSS class. I'm somewhat stuck though.

My problem is, I can successfully set the state value in the global store. However, I do not know how to react to property value changes in the components. I added a watchEffect, in my setup functions. However, that does not give me access to the state of the individual component itself. I'm trying to figure out a way in each component to say "hey, when this property in the store changes, update the UI like this.".

What am I missing?

Upvotes: 3

Views: 2528

Answers (1)

tony19
tony19

Reputation: 138336

You could use a computed() prop to track the state's value (e.g., to test whether it's even):

const MyApp = {
  setup() {
    return {
      isEven: computed(() => store.state.result % 2 === 0)
    }
  }
}

Then, use that prop in the template to apply a conditional class:

<content :class="{ 'even-content': isEven, 'odd-content': !isEven }">

updated fiddle

Upvotes: 5

Related Questions