29일차 - Vue: Computed, Watch, Class & StyleBinding

변승훈·2022년 5월 8일
0

Computed

  • 계산된 데이터, 계산된 데이터는 데이터 옵션에 정의한 특정한 데이터를 추가적으로 연산을 통해 정의를 한 다음 그 값은 반환해서 사용할 수 있는 새로운 계산된 데이터이다.
  • 캐싱기능이 존재하며 한 번 연산해둔 값이 있다면 재 연산 하지 않는다.
  • getter, setter(값을 얻어 내거나 값을 지정)로 사용할 수 있다.

예시를 통해 이해해보자!

  1. Computed를 Getter로 사용하는 경우
<template>
  <!-- 이중 중괄호 문법 사이에 표현식을 작성할 수 있다. -->
  <h1>{{ msg + '??' }}</h1>
  <h1>{{ msg.split('').reverse().join('') }}</h1>

  <button @click="add">
    ADD
  </button>
  <h1>{{ reverseMessage() }}</h1>
  <h1>{{ reverseMessage() }}</h1>
  <h1>{{ reverseMessage() }}</h1>
  <h1>{{ reverseMessage() }}</h1>
</template>
<script>
  export default {
    data() {
      return {
        msg: 'Hello Computed!'
      }
    },
    computed: {
      // 1. Getter로 사용하는 경우
       reversedMessage() {
         return this.msg.split('').reverse().join('')
         // 'Apple' => ['A','p','p','l','e']
         // => ['e','l','p','p','A'] => 'elppA'
    },
    methods: {
      reverseMessage() {
        return this.msg.split('').reverse().join('')
      },
      add() {
        // Getter로 사용하는 경우 읽기 전용(Readonly)이기 때문에 
        // 할당 연산자를 통해 값을 할당 하더라도 반응적으로 동작할 수 없다.
        this.reversedMessage += '!?'
      }
    }
  }
</script>

위의 template태그의 내용 처럼 여러번을 반복할 경우 메소드를 사용하면 나올 때 마다 연산을 해야한다. 만약 몇 십, 몇 백개가 연산을 하게 된다면 자연스럽게 과부하가 오기 때문에 이렇게 사용하면 안된다.

이것을 해결하기 위해 computed를 사용한다.

  1. Computed를 Getter, Setter로 사용하는 경우
<template>
  <!-- 이중 중괄호 문법 사이에 표현식을 작성할 수 있다. -->
  <h1>{{ msg + '??' }}</h1>
  <h1>{{ msg.split('').reverse().join('') }}</h1>
  <!-- 여러 번 반복 시 메소드 대신 computed의 캐시 기능을 사용한다. -->
  <button @click="add">
    ADD
  </button>
  <h1>{{ reversedMessage }}</h1>
  <h1>{{ reversedMessage }}</h1>
  <h1>{{ reversedMessage }}</h1>
  <h1>{{ reversedMessage }}</h1>
</template>
<script>
  export default {
    data() {
      return {
        // Getter, Setter: 값을 얻어내거나 값을 지정하는 용도로 사용할 수 있다.
        msg: 'Hello Computed!'
      }
    },
    computed: {
      // Getter, Setter로 사용하는 경우, 위의 data()와 연결되어 있다.
      reversedMessage: {
        // Getter, 값을 얻어내는 용도
        get() {
          return this.msg.split('').reverse().join('')
          // 'Apple' => ['A','p','p','l','e']
          // => ['e','l','p','p','A'] => 'elppA'
        },
        // Setter, 값을 할당하는 용도
        set(v) { 
          this.msg = v
          // 1. 버튼을 누를 경우 아래의 add()가 실행된다.
          // 2. reversedMessage에 '!?'가 + 되면서 v에 들어온다.
          // 3. v가 msg 데이터에 할당이 된다.
          // 4. 변경된 값이 get()으로 가서 새로 변경된 값을 return통해 반환하여 
          //    화면에 출력
        }
      }
    },
    methods: {
      reverseMessage() {
        return this.msg.split('').reverse().join('')
      },
      add() {
        // Getter와 Setter 둘 다 사용하는 경우에서 이를 해결한다.
        this.reversedMessage += '!?'
      }
    }
  }

1번의 reverseMessage() 메소드를 reversedMessage로 바꿔서 출력해 보았다.
computed를 사용하게 되면 나올 때 마다 연산해서 출력하지 않아(캐싱) 부담이 줄어 든다.
즉, 데이터를 최적화 하는 용도로 사용할 수 있으며 원본의 데이터를 손상시키지 않고 계산을 한다.

Watch

Watch는 감시하는 데이터들이 변경되는 것을 감지할 때 실행된다.

감시하고 싶은 데이터가 있다면 watch부분에 메소드처럼 만들어 메소드의 로직으로 그 데이터가 변경됐을때 어떤 내용을 실행할 것인지를 명시해주면 된다.

쉽게 말하자면 데이터들의 변경 사항들을 감시하는 옵션이다.

아래의 예시를 참고하자!

<template>
  <h1 @click="changeMessage">
    {{ msg }}
  </h1>
  <h1>{{ reversedMessage }}</h1>
</template>
<script>
  export default {
    data() {
      return {
        msg: 'Hello Watch?'
      }
    },
    computed: {
       reversedMessage() {
         return this.msg.split('').reverse().join('')
      }
    },
    watch: {  
      // 감시하는 데이터들이 변경되는 것을 감지할 때 실행된다.
      // 데이터들의 변경사항들을 감시하는 옵션이다.
      
      // 1. 매개변수 이용 X
      msg() {
        // 변경이 일어났을 때 console.log를 출력
      	console.log('msg: ', this.msg)
        
      // 2. 매개변수를 이용 O
      msg(v) {
        console.log('msg: ', v)
      },
      // 계산된 데이터도 감시할 수 있다.
      reversedMessage() {
        console.log('reversedMessage: ', this.reversedMessage)
      }
    },
    methods: {
      // click시 msg를 'Good!'으로 변경시키는 메소드
      changeMessage() {
        this.msg = 'Good!'
      }
    }
  }
</script>

Class & Style Binding

1. HTML 클래스 바인딩

1-1. 객체 구문

:class에 객체를 전달하여 클래스를 동적으로 전환할 수 있다.

  • 사용 예시
<template>
<!-- class binding -->
  <h1 
  :class="{ active: isActive }" 
  @click="activate">
    Hello?!({{ isActive }})
  </h1>
</template>
<script>
export default {
  data() {
    return {
      isActive: false
    }
  },
  methods: {
    activate() {
      this.isActive = true
    }
  }
}
</script>
<style scoped>
  .active {
    color: red;
    font-weight: bold;
  } 
</style>

위의 예시에서 active 클래스의 존재가 데이터 속성 isActive의 true, false에 의해 결정됨을 의미한다.

  • 바인딩 된 객체는 '인라인'일 필요는 없다.
<div :class="classObject"></div>
data() {
  return {
    classObject: {
      active: true,
      'text-danger': false
    }
  }
}
  • 객체를 반환하는 computed property에 바인딩 할 수도 있다.
<div :class="classObject"></div>
data() {
  return {
    isActive: true,
    error: null
  }
},
computed: {
    classObject() {
      return
     	 active: this.isActive && !this.error,
      	'text-danger': this.error && this.error.type === 'fatal'
    }
  }
}

1-2. 배열 구문

배열은 :class에 전달하여 클래스 목록을 적용할 수 있다.

<div :class="[activeClass, errorClass]"></div>
data() {
  return {
    activeClass: 'active',
    errorClass: 'text-danger'
    }
  }
}

위는 아래와 같이 렌더링 된다.

<div :class="active text-danger"></div>

2. 인라인 스타일 바인딩 하기

2-1. 객체 구문

:style의 객체 구문은 매우 간단하며 JavaScript 객체라는 점을 제외하면 CSS와 거의 비슷하다.
CSS 속성 이름에는 camelCase 또는 kebab-case를 사용할 수 있다.

<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data() {
  return {
    activeColor: 'red',
    fontSize: 30
    }
  }
}
  • 템플릿을 더 깔끔하게 만들기 위해 스타일 객체에 직접 바인딩 하는 것이 좋다.
<div :style="styleObject"></div>
data() {
  return {
    styleObject: {
      color: 'red',
      fontSize: '13px'
      }
    }
  }
}
  • 사용 예시
<template>
  <h1 
  :style="{
    color,
    fontSize
  }"
  @click="changeStyle">
  Hello?!
  </h1>
</template>
<script>
export default {
  data() {
    return {
      color: 'orange',
      fontSize: '30px'
    }
  },
  methods: {
    changeStyle() {
      this.color = 'red',
      this.fontSize = '50px'
    }
  }
}
</script>

2-2. 배열 구문

:style에 대한 배열 구문은 같은 스타일의 엘리먼트에 여러 개의 스타일 객체를 사용할 수 있게 한다.

<div :style="[baseStyles, overridingStyles]"></div>
  • 사용 예시
<template>
  <h1 
  :style="[fontStyle, backgroundStyle]"
  @click="changeStyle">
  Hello?!
  </h1>
</template>
<script>
export default {
  data() {
    return {
      fontStyle: {
        color: 'orange',
        fontSize: '30px'
      },
      backgroundStyle: {
        backgroundColor: 'black'
      }
    }
  },
  methods: {
    changeStyle() {
      this.fontStyle.color = 'red',
      this.fontStyle.fontSize = '50px'
    }
  }
}
</script>
profile
잘 할 수 있는 개발자가 되기 위하여

0개의 댓글