Phil
Phil

Reputation: 815

How to flatten a computed object without losing reactivity

I'm using a computed object. I want to expose the properties of that object in the setup function, but I haven't found how.

export default {
  setup() {
    const counter = Vue.ref(0)
    const data = Vue.computed(() => ({
      plus1: counter.value + 1,
      plus2: counter.value + 2,
    }))
    const increment = () => {
      counter.value++
    }
    
    return {
      counter,
      plus1: data.value.plus1, // This is bad, no reactivity
      plus2: data.value.plus2,
      increment
    }
  },
};

Full code pen here : https://codepen.io/philfontaine/pen/KKmzJrK

EDIT

Alternatives I have considered:

But these are alternatives, not how I really wished it could work.

Upvotes: 1

Views: 383

Answers (2)

Phil
Phil

Reputation: 815

You cannot directly flatten a computed object (no API is currently provided to do that).

I ended up resorting to using the computed object directly in the template.

Upvotes: 0

matthew-e-brown
matthew-e-brown

Reputation: 3062

You could use a reactive object with toRef instead.

Vue.createApp({
  setup() {
    const counter = Vue.ref(0);

    const data = Vue.reactive({
      get plus1() { return counter.value + 1; },
      get plus2() { return counter.value + 2; },
    });

    const increment = () => counter.value++;

    return {
      counter,
      plus1: Vue.toRef(data, 'plus1'),
      plus2: Vue.toRef(data, 'plus2'),
      increment
    }
  }
}).mount('#app');
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}

a, button {
  color: #4fc08d;
}

button {
  background: none;
  border: solid 1px;
  border-radius: 2em;
  font: inherit;
  padding: 0.75em 2em;
  margin: 0.85em;
}
<script src="https://unpkg.com/vue@next"></script>

<div id="app">
  <div>{{ counter }}</div>
  <div>{{ plus1 }}</div>
  <div>{{ plus2 }}</div>
  <button @click="increment">Increment</button>
</div>

Although, this is a little awkward to me. I would use some other method if possible; why do plus1 and plus2 need to be a part of the same object? What's wrong with

const counter = ref(0);
const plus1 = computed(() => counter.value + 1);
const plus2 = computed(() => counter.value + 2);

this? I'm sure your real example is much more complex, but it may be worth thinking about: computed is the intuitive thing to use here, and on individual variables.

Upvotes: 2

Related Questions