惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Docker
Simon Willison's Weblog
Simon Willison's Weblog
H
Help Net Security
F
Fortinet All Blogs
H
Heimdal Security Blog
S
Schneier on Security
L
LangChain Blog
博客园 - Franky
酷 壳 – CoolShell
酷 壳 – CoolShell
NISL@THU
NISL@THU
P
Palo Alto Networks Blog
J
Java Code Geeks
博客园 - 【当耐特】
The Last Watchdog
The Last Watchdog
W
WeLiveSecurity
www.infosecurity-magazine.com
www.infosecurity-magazine.com
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Vulnerabilities – Threatpost
I
InfoQ
Recorded Future
Recorded Future
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
CERT Recently Published Vulnerability Notes
T
Tenable Blog
腾讯CDC
C
Check Point Blog
量子位
M
MIT News - Artificial intelligence
GbyAI
GbyAI
罗磊的独立博客
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
B
Blog
小众软件
小众软件
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
CXSECURITY Database RSS Feed - CXSecurity.com
Stack Overflow Blog
Stack Overflow Blog
P
Proofpoint News Feed
P
Privacy & Cybersecurity Law Blog
V2EX - 技术
V2EX - 技术
T
Threatpost
Engineering at Meta
Engineering at Meta
Attack and Defense Labs
Attack and Defense Labs
T
Tailwind CSS Blog
S
Securelist
The Cloudflare Blog
博客园 - 叶小钗
L
LINUX DO - 最新话题
T
Troy Hunt's Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
爱范儿
爱范儿

The Tracks of mulder21c

Atomic Design + Storybook 적용 후기 json-server에 사용자 인증 구현하기 개발환경 WSL2 + zsh로 갈아타기 2020년 회고 colum flexbox에서 padding bottom 문제 해결 Nuxt를 통해 보는 프론트엔드 개발자가 하는 일 Nuxt Router kebab-case 처리 JS to SCSS 변환 Nuxt + Storybook 통합 하기 2020 이직 이야기 2020 이직 이야기 2020 이직 이야기 2020 이직 이야기 Windows에서 PM2 실행 오류 해결 오픈톡 정지에 대한 카카오톡 고객센터 후기 배려에 대한 단상 학습이 잘 되지 않는 이유 웹팩 4 마이그레이션 삽질기 babel 7 업데이트 후 node_modules 패키지가 변환되지 않는다면? white space는 4px이다? 정말? 2020년 시간 관리를 위해서 도입 한 툴들 Codility Lesson 5 — PassingCars 2019년 회고 Codility Lesson 4 — MissingInteger Codility Lesson 4 — MaxCounters Codility Lesson 4 — FrogRiverOne Codility Lesson — PermCheck 착각은 자유가 아닌각 세미나 진행 후기 Codility Lesson 3 — tapeEquilibrium Codility Lesson 3 — PermMissingElm Codility Lesson 3 — FrogJump 알고리즘 연습을 다시 시작했다. Codility Lesson 2 — CyclicRotation Codility Lesson 2 — OddOccurrencesInArray Codility Lesson 1 — BinaryGap 아이패드 구매 하고 3주 써 본 기록 세미나 어떻게 준비해야 할까? HTML은 웹이다 접근성 향상을 위한 이름 짓기 접근성 교육에서 자주 나오는 상위 5가지 질문 접근 가능한 숨김 텍스트 깃북 파일 저장 시 오류 문제 해결 크로스 브라우징이란? 블로그 테마 만들기 시작 2018년 회고 학습에 대한 오해 모르는 사람에게 질문할거면 예의 좀 지켜라 파이썬으로 웹 크롤러 만들기 해쉬 링크 오프셋 조정하기
pass function as props in vue
멀더끙 · 2021-01-24 · via The Tracks of mulder21c

Event handling and Atomic Design System

Atomic Design System을 컴포넌트 설계 방법론으로 가져가면서, 각 컴포넌트에 독립적으로 고립(?)된 데이터 구조를 만들게 되면서 (이게 맞는 방식인지는 잘 모르겠지만) 불편함이 점점 발생되었던 것 중 하나가 유저 인터랙션에 의해 발생되는 데이터 변경을 위해 쌓여진 컴포넌트 구조를 따라 계속 이벤트를 전달하고 이벤트 리스너를 통해 처리하는 방식이었다.

예를 들자면

유저 인터랙션으로 하위 컴포넌트로부터 상위 컴포넌트로의 이벤트 발생 과정

이런 흐름 말이다.

Vue 공식 문서도 그렇고, 지금까지 보아온 대다수의 강의에서도 유저 인터랙션에 대한 데이터를 처리할 때 해당 데이터가 상위 컴포넌트에 존재할 경우, $emit을 이용하여 payload와 함께 하위 컴포넌트로부터 상위 컴포넌트로 차례로 올리고, 상위 컴포넌트에서 v-on으로 처리하는 방식을 사용하도록 안내하는 듯 하다.

Atomic Design Sytem을 적용하기 전에는 이러한 고민이 없었는데, 적용 이후로는 atom으로부터 실제 데이터가 바인딩 되는 page까지 5개 단계(?)를 거치게 되니 하위 컴포넌트에서 발생한 이벤트와 데이터를 다시 상위 컴포넌트로 by-pass 하기 위한 이벤트 처리가 뭐랄까... 조금 거슬린다고 할까?
심지어 Vue 개발자 도구로 데이터 흐름을 확인하려고 하면 한 번의 인터랙션에 여러 개의 emit이 로그로 출력되니 정신이 사납기까지 한 느낌이다 = _=a

그래서 props로 이벤트 핸들러를 내려주고, 가장 기저에 있는 atom에 해당하는 컴포넌트가 이 핸들러를 실행시키기만 하면 어떨까 하는 생각에 prop로 함수를 내려주는 방식을 생각해보게 됐다.

Is it an anti-pattern?

일단 생각을 해 봤으니 이게 가한 것은 맞는지 확인 해 볼 필요가 있었다. (처음 생각해 본 방법이고 Vue 관련 문서나 강의에서도 한 번도 이런 케이스를 본 적이 없으니까..)

구글링 결과 공교롭게도(?) 가장 먼저 눈에 띈 내용은 이 방식이 안티 패턴이라는 내용이었다.
(혹 관련 내용이 궁금하다면 How to Pass a Function as a Prop in Vue를 읽어보시길... 아, 중간에 구독하라고 전체 팝업창이 뜨기는 하는데 개발자라면 뭐... 다 쉽게 걷어내... 쿨럭... )

하지만 왜 인지 모르겠으나... 해당 글에서는 안티 패턴임을 설명하는데 하위 컴포넌트의 mounted 훅에서 props로 받은 함수를 실행하는 코드를 보여주고 있었다.
무튼 그러면서 잘못된 것은 아니지만, Vue의 컨셉에 맞게 이벤트를 활용하거나 슬롯을 사용하라는 결론을 내주는게 영...

또 다른 아티클 들에서는 단순하게 props로 함수를 내리는게 가능하다 라는 짤막한 소개 정도가 있었다.

하여 안티 패턴이라 소개하는 글을 잠시 무시하기로 하고(?) props로 함수를 내리는 방식을 사용해봤다.
아, 안티 패턴이라 소개하는 글을 무시하기로 한 것은 안티 패턴을 굳이 사용하겠다는 것이 아니라, 안티 패턴인 이유에 대한 명확한 근거를 찾을 수 없어서다. 차후에라도 이것이 안티 패턴이라는 명확한 근거를 찾게 된다면 당연히 과감히 버릴거다.

Try it

<template>
  <SignUpTemplate :handle-sign-up="signUp" />
</template>
<script>
export default {
  ...
  methods: {
    ...
    signUp({ email, password }) {
      users
        .postSignUp({ email, password })
        .then(...)
        .catch(...)
    }
  }
};
</script>

Page에서 이렇게 signUp 함수를 props로 내려주고

<template>
  ...
  <SignUpForm :handle-submit="handleSignUp" />
  ...
</template>

<script>
export default {
  ...
  props: {
    ...
    handleSignUp: {
      type: Function,
      required: true,
      default: () => {}
    }
  },
  ...
};
</script>

템플릿에서 props로 받은 함수를 다시 하위 컴포넌트로 내려주고,

<template>
  <form-container>
    ...
    <DefaultButton
      @click.native.prevent="handleClickSubmit"
    />
    ...
  </form-container>
</template>

<script>
import DefaultButton from "@atoms/Button/Default";
export default {
  components: {
  props: {
    handleSubmit: {
      type: Function,
      required: true,
      default: () => {}
    }
  },
  methods: {
    handleClickSubmit() {
      const { handleSubmit, email, password, passwordConfirm } = this;
      ...
      handleSubmit && handleSubmit({ email, password });
    }
  }
};
</script>

유저 인터랙션이 발생하는 하위 컴포넌트에서 해당 함수를 전달받아 실행하게 했다.
적용 결과는 당연히(?) 원하는 동작을 올바르게 수행해주었다.

이것보다는 modal 창을 포함하는 organism 컴포넌트에서 modal 창에 대한 제어와 modal 내부에 slot으로 끼워진 컴포넌트에 적용되는 부분이 이 방식을 더 잘 설명할 수 있을 것 같지만 너무 많은 코드가 삽입 되어야 해서 포스팅에는 간단한 위 코드로 적었다.

사실 event emit 방식으로도 충분히 대체도 가능하고 그것이 난이도나 복잡도가 더 높지는 않은 것 같기는 하다. 하지만, 뭐랄까 이 방식이 좀 더 dry한 느낌이 든달까? (기분탓이려나?)

무엇보다 개발자 도구에 여러 번에 걸친 이벤트 발생 로그를 보지 않아도 되니 한결 눈이 가벼워졌다.