티스토리 뷰

 

화면에서 computed 속성의 값을 변경 시킬 경우 발생하는 오류와 이에 대한 해결 방법을 이야기하고자 한다.

먼저, 아래의 소스를 보자.

  <template>
      <div>
          <p>computed 값: {{ compDefaultValue }}</p>
          <button @click="increase">문구 변경</button>
      </div>
  </template>

  <script>
  export default {
      data: () => ({
          defaultValue: 0
      }),
      computed: {
          compDefaultValue() {
              return this.defaultValue
          }
      },
      methods: {
          increase() {
              this.compDefaultValue = 1
          }
      }
  }
  </script>

 
위 소스에서 문구 변경을 클릭할 경우 호출되는 increase 함수에서 this.compDefaultValue = 1 을 하는 순간 아래와 같은 오류가 발생할 것이다.

 

vue.runtime.esm.js:619 [Vue warn]: Computed property "compDefaultValue" was assigned to but it has no setter.

 

computed 내 에서 사용되는 속성들은 단어그대로 계산된 속성 (computed properties) 이 정의되는 것인데

이는 명시적으로 값을 설정하지 않는 읽기 전용 으로 설계되어 있다.

이렇게 읽기 전용으로 설계 된 속성을 변경하려하면 위와 같은 오류가 발생하게 된다.

만약 값을 수정해야 할 필요가 있을때는 get()set() 메소드를 사용하면 된다.

 

get()

정의 된 값을 반환한다. getter 라고 표현한다.

 

set()

정의 된 값을 수정한다. setter 라고 표현한다.

 

getter, setter 를 사용하여 수정된 소스는 아래와 같다.

  <template>
    <div>
        <p>computed 값: {{ compDefaultValue }}</p>
        <button @click="increase()">값 증가</button>
    </div>
  </template>

  <script>
  export default {
      data: () => ({
          defaultValue: 0
      }),
      computed: {
          compDefaultValue: {
              get() {
                  return this.defaultValue
              },
              set(newValue) {
                  this.defaultValue = this.defaultValue + newValue
              }
          }
      },
      methods: {
          increase() {
              this.compDefaultValue = 1
          }
      }
  }
  </script>

이제 값 증가 버튼을 클릭하면 setter (set()) 를 통해 전달된 1 값이 기존 defaultValue 값에 더해지고,
화면에는 getter (get()) 를 통해 자동으로 업데이트 된 값이 표시된다.

 

여기서 한가지 체크할 부분은.. 사실 아래와 같이 increase 함수에서 defaultValue 값 자체를 증가시키면 좀 더 간단하게 해결이 된다.

  <template>
    <div>
      <p>computed 값: {{ compDefaultValue }}</p>
      <button @click="increase">값 증가</button>
    </div>
  </template>

  <script>
  export default {
    data: () => ({
      defaultValue: 0
    }),
    computed: {
      compDefaultValue() {
          return this.defaultValue
      }
    },
    methods: {
      increase() {
          this.defaultValue = this.defaultValue + 1
      }
    }
  }
</script>

 

하지만 getter, setter 가 필요한 경우가 있는데 예를들면 체크박스를 사용할 때와 같은 경우이다.

아래의 예제는 vuex 를 사용 시 storestate 의 변수값을 이용하여 체크박스를 사용하는 예제이다.

(v-checkbox 는 vuetify2 (https://vuetifyjs.com)에서 사용되는 요소 선언이다.)


  ...store: main.js

  export default {
    namespace: true,
    state: {
      checkAll: false
    }
    ...
  }

  ...template: main.vue  

  <template>
    <div>
      <v-checkbox
        v-model="checkAll"
        :label="`value: ${checkAll}`"
      ></v-checkbox>
    </div>
  </template>

  <script>

  import {mapState} from 'vuex'
  export default {
    computed: {
      ...mapState('main', {
          checkAll: state => state.checkAll
      })
    }
  }
</script>

 

위와 같이 작성하였을 경우 본문에서 언급한 setter 오류가 동일하게 발생한다.

이때 간단하게 해결 할 수 있는 방법이 getter, setter 를 이용한 방법이다.

수정 된 코드는 아래와 같다.

 

store: main.js


  export default {
    namespace: true,
    state: {
      checkAll: false
    }
    ...

    mutations: {
      setCheckAll(state, v) {
        state.checkAll = v
      }
    }
  }

 

template: main.vue

  <template>
    <div>
      <v-checkbox
        v-model="compCheckAll"
        :label="`value: ${compCheckAll}`"
      ></v-checkbox>
    </div>
  </template>

  <script>

  import {mapState} from 'vuex'
  export default {
    computed: {
      ...mapState('main', {
          checkAll: state => state.checkAll
      }),
      compCheckAll: {
        get() {
          return this.checkAll
        },
        set(v) {
          this.$store.commit('main/setCheckAll', v)
        }
      }
    }
  }
</script>

 

이렇게 하면 checkbox 를 클릭 할 때마다 storemutations 에 설정 된 setCheckAll 함수가 호출되며

이때 변경 된 값을 전달하게 되고, 그 값은 바로바로 화면에 표시 될 것이다.

 

댓글