rfcs icon indicating copy to clipboard operation
rfcs copied to clipboard

The better way to code。

Open LastHeaven opened this issue 5 years ago • 5 comments

Basic example

<template>
  <div>
    <div>
      <span>double:</span><span>{{double}}</span>
    </div>
    <button @click="inc">Clicked {{ count }} times.</button>

    <div>
      <div><input type="number" v-model="form.a"></div>
      <div><input type="number" v-model="form.b"></div>
      <div>
        <span>a + b:</span>
        <span>{{result1}}</span>
      </div>
      <div>
        <span>a + count:</span>
        <span>{{result2}}</span>
      </div>
      <div>
        <span>b + count:</span>
        <span>{{result3}}</span>
      </div>
      <div>
        <span>a + b + double:</span>
        <span>{{result4}}</span>
      </div>
    </div>
  </div>
</template>

<script>
import { ref, reactive, computed } from 'vue'

export default {
  setup () {
    const form = reactive({
      a: 1,
      b: 2
    })
    const count = ref(0)

    const inc = () => {
      count.value++
    }

    const double = computed(() => {
      return count.value * 2
    })

    const result1 = computed(() => {
      return form.a + form.b
    })

    const result2 = computed(() => {
      return form.a + count.value
    })

    const result3 = computed(() => {
      return form.b + count.value
    })

    const result4 = computed(() => {
      return form.a + form.b + double.value
    })

    return {
      form,
      count,
      double,
      result1,
      result2,
      result3,
      result4,
      inc
    }
  }
}
</script>

The usage of .value is easy to make Bug.
So I think the better way is like this.

<template>
  <div>
    <div>
      <span>double:</span><span>{{double}}</span>
    </div>
    <button @click="inc">Clicked {{ count }} times.</button>

    <div>
      <div><input type="number" v-model="form.a"></div>
      <div><input type="number" v-model="form.b"></div>
      <div>
        <span>a + b:</span>
        <span>{{result1}}</span>
      </div>
      <div>
        <span>a + count:</span>
        <span>{{result2}}</span>
      </div>
      <div>
        <span>b + count:</span>
        <span>{{result3}}</span>
      </div>
      <div>
        <span>a + b + double:</span>
        <span>{{result4}}</span>
      </div>
    </div>
  </div>
</template>

<script>
import { toRefs, reactive, computed } from 'vue'

export default {
  setup () {
    const state = reactive({
      form: {
        a: 1,
        b: 2
      },
      count: 0
    })

    const inc = () => {
      state.count++
    }

    state.double = computed(() => {
      return state.count * 2
    })

    state.result1 = computed(() => {
      return state.form.a + state.form.b
    })

    state.result2 = computed(() => {
      return state.form.a + state.count
    })

    state.result3 = computed(() => {
      return state.form.b + state.count
    })

    state.result4 = computed(() => {
      return state.form.a + state.form.b + state.double
    })

    return {
      ...toRefs(state),
      inc
    }
  }
}
</script>

No more .value,just like state instead of this in vue2.

LastHeaven avatar Jan 21 '20 07:01 LastHeaven

I proposed exactly the same previously. But then after using the API for a while it became clear to me that ref is amazing.

ycmjason avatar Jan 21 '20 07:01 ycmjason

There is nothing to stop you from coding in that style tho. Feel free to do whatever you prefer?

ycmjason avatar Jan 21 '20 07:01 ycmjason

One big thing that does not work with reactive is TypeScript support. Even simple things like this don't compile with TypeScript without declaring a separate interface

const state = reactive({
  a: 1,
  b: 2,
  c: computed(() => {
    return state.a * state.b
  })
})

And even though everyone seem to embrace better TypeScript support - all the examples don't use it or just use ref instead. Even official ones.

So if you need TypeScript you either get used to write value & ref everywhere or get used to write interfaces for TypeScript & reactive (or hope that some day TS will compile recursive types). ref seems like a better option in the end.

vmihailenco avatar Jan 21 '20 07:01 vmihailenco

To be precise - it compiles, but state has type any (so no point in using TypeScript) - 'state' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.

vmihailenco avatar Jan 21 '20 08:01 vmihailenco

The .value is necessary and described at https://vue-composition-api-rfc.netlify.com/#ref-vs-reactive This was largely discussed during the RFC process at https://github.com/vuejs/rfcs/pull/78 and the previous one at #42 (that's why it has a note on the RFC website)

posva avatar Jan 21 '20 09:01 posva