Vue 는 왜$attrs 와$listeners 를 신중하게 사용 합 니까?
10283 단어 Vue$attrs$listeners
Vue
개발 과정 에서 조상 구성 요 소 를 만나면 손자 구성 요소 에 값 을 전달 해 야 할 때 아들 구성 요소props
를 받 은 다음 에 손자 구성 요소 에 전달 해 야 한다.사용v-bind="$attrs"
을 통 해 큰 편 의 를 가 져 다 줄 수 있 지만 위험 도 있다.위험
먼저 예 를 들 어 보 겠 습 니 다.
부모 구성 요소:
{
template: `
<div>
<input
type="text"
v-model="input"
placeholder="please input">
<test :test="test" />
</div>
`,
data() {
return {
input: '',
test: '1111',
};
},
}
하위 구성 요소:
{
template: '<div v-bind="$attrs"></div>',
updated() {
console.log('Why should I update?');
},
}
입력 상자 에 값 을 입력 할 때input
필드 만 수정 하여 부모 구성 요 소 를 업데이트 하 는 것 을 볼 수 있 습 니 다.하위 구성 요소 의 propstest
는 수정 되 지 않 았 습 니 다. ,
기준 으로 볼 때 하위 구성 요 소 는 트리거updated
방법 을 업데이트 하지 말 아야 합 니 다.왜 일 까요?그래서 나 는 이'bug'를 발견 하고 신속하게 열 었 다
gayhub
.나 도 중대 한 오픈 소스 프로젝트 에 참여 한 사람 이 라 고 생각 하고 깜짝 놀 랐 다.사실 이 잔혹 하 다.이렇게 뚜렷 한 문제 가 어떻게 아직 발견 되 지 않 았 을 수 있 겠 는가..무정 하 다..........................................................................
그럼"bug"가 아 닌 이상 왜 그런 지 봅 시다.
원인
먼저 전 제 를 소개 합 니 다.
issue
구성 요 소 를 업데이트 할 때 해당 하 는Vue
과data
트리거props
알림 을 업데이트 하여 렌 더 링 을 업데이트 하 는 것 입 니 다.모든 구성 요 소 는 유일 하 게 대응 하 는
Watcher
이 있 기 때문에 하위 구성 요소Watcher
가 업데이트 되 지 않 았 을 때 하위 구성 요소 의 업 데 이 트 를 촉발 하지 않 습 니 다.우리 가 하위 구성 요소 의props
를 제거 할 때v-bind="$attrs"
갈고리 가 더 이상 실행 되 지 않 기 때문에 문제 가 여기에 나타 난 것 을 발견 할 수 있다.원인 분석
updated
원본 코드 에서 검색Vue
,파일 찾기$attrs
:
export function initRender (vm: Component) {
// ...
defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, null, true)
defineReactive(vm, '$listeners', options._parentListeners || emptyObject, null, true)
}
오,놀 랍 군!바로 그것 이다.src/core/instance/render.js
방법 에서initRender
속성 을$attrs
에 연결 하고 응답 식 대상 으로 설정 하여 비밀 발견 에 한 걸음 더 가 까 워 진 것 을 볼 수 있다.수집 에 의존 하 다
우 리 는
this
이Vue
방법 을 통 해 수집 에 의존 할 것 이라는 것 을 알 고 있다.이 부분 도 비교적 많 기 때문에 여 기 는 간단 한 이해 만 할 수 있다.
Object.defineProperty(obj, key, {
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend() // -- Dep.target.addDep(dep)
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
}
})
Object.defineProperty
에 대한 납 치 를 통 해 우 리 는get
를 방문 할 때$attrs
dep
가 있 는$attrs
을Watcher
의dep
에 수집 하여 설정 할 때 배포 업데이트subs
를 하고 보기 렌 더 링 을 알 립 니 다.업 데 이 트 를 배포 하 다.
다음은 응답 식 데 이 터 를 바 꿀 때 업 데 이 트 를 보 내 는 핵심 논리 입 니 다.
Object.defineProperty(obj, key, {
set: function reactiveSetter (newVal) {
const value = getter ? getter.call(obj) : val
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = !shallow && observe(newVal)
dep.notify()
}
})
아주 간단 한 일부 코드 는 응답 식 데이터 가notify()
되 었 을 때 호출set
하 는dep
방법 으로 각각notify
을 옮 겨 다 니 며 업데이트 하 는 것 이다.
notify () {
// stabilize the subscriber list first
const subs = this.subs.slice()
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update()
}
}
이러한 기 초 를 알 게 된 후에 우 리 는Watcher
이 어떻게 하위 구성 요 소 를 촉발 하 는$attrs
방법 을 되 돌아 보 았 다.하위 구성 요소 가 업 데 이 트 될 것 이라는 것 을 알 아야 합 니 다.어 딘 가 에 방문 한 것 이 분명 합 니 다
updated
.수집$attrs
에 의존 해 야 배포 할 때 업데이트 가 필요 하 다 는 통 지 를 받 을 수 있 습 니 다.우 리 는 추가subs
와 추가 하지 않 음v-bind="$attrs"
을 비교 하여 소스 코드 를 디 버 깅 하면 볼 수 있 습 니 다.
get: function reactiveGetter () {
var value = getter ? getter.call(obj) : val;
if (Dep.target) {
dep.depend();
if (childOb) {
childOb.dep.depend();
if (Array.isArray(value)) {
dependArray(value);
}
}
}
var a = dep; // dep
debugger; // debugger
return value
}
바 인 딩v-bind="$attrs"
시 의존 도 를 하나 더 수집 합 니 다.하나
v-bind="$attrs"
가id
인8
에서 수집dep
이 있 는$attrs
이 있 습 니 다.유 무Watcher
시의v-bind="$attrs"
를 비교 해 보 겠 습 니 다.배포 업데이트 상태:
set: function reactiveSetter (newVal) {
var value = getter ? getter.call(obj) : val;
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter();
}
if (setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
childOb = !shallow && observe(newVal);
var a = dep; // dep
debugger; // debugger
dep.notify();
}
여기 서 분명히 볼 수 있 듯 이
set
id
을 위 한8
이 옮 겨 다 니 며dep
알림subs
을 업데이트 하려 고 준비 하고 있 고Watcher
과newVal
도 볼 수 있다.사실 값 은 변 하지 않 고 업데이트 되 었 다.
질문:$attrs 의 의존 은 어떻게 수집 되 었 습 니까?
우 리 는 수집 에 의존 하 는 것 이
value
에서 이 루어 졌 다 는 것 을 알 고 있 지만,우리 가 초기 화 할 때 데 이 터 를 방문 하지 않 았 다 면 어떻게 이 루어 졌 을 까?답 은
get
이 방법 으로 생 성vm._render()
되 고 이 과정 에서 데 이 터 를 방문 하여 의존 도 를 수집 하 는 것 이다.그래도 이 문 제 를 풀 지 못 했 군요.서 두 르 지 마 세 요.이것 은 방석 입 니 다.
Vnode
에서 도 어디서 방 문 했 는 지 찾 을 수 없 기 때 문 입 니 다vm._render()
.유암 화 명
우리 의 코드 와
$attrs
모두vm._render()
에 접근 하지 않 았 습 니 다.이 유 는$attrs
에 만 나타 날 수 있 기 때 문 입 니 다.우 리 는v-bind
을 사용 하여 템 플 릿 을 컴 파일 해 보 겠 습 니 다.
const compiler = require('vue-template-compiler');
const result = compiler.compile(
// `
// <div :test="test">
// <p> </p>
// </div>
// `
`
<div v-bind="$attrs">
<p> </p>
</div>
`
);
console.log(result.render);
// with (this) {
// return _c(
// 'div',
// { attrs: { test: test } },
// [
// _c('p', [_v(' ')])
// ]
// );
// }
// with (this) {
// return _c(
// 'div',
// _b({}, 'div', $attrs, false),
// [
// _c('p', [_v(' ')])
// ]
// );
// }
이것 이 최종 방문vue-template-compiler
의 곳 입 니 다.따라서$attrs
은 의존 에 수 집 됩 니 다.$attrs
에서input
의 값 이 업데이트 되 었 을 때v-model
업데이트 알림 을 터치 하고 구성 요 소 를 업데이트 할 때 호출 되 는set
방법 에서updateChildComponent
에 값 을 부여 합 니 다.
// update $attrs and $listeners hash
// these are also reactive so they may trigger child update if the child
// used them during render
vm.$attrs = parentVnode.data.attrs || emptyObject;
vm.$listeners = listeners || emptyObject;
그래서 트리거$attrs
의$attrs
를 촉발 하여 그 가 있 는set
을 업데이트 시 키 고 하위 구성 요소 의 업 데 이 트 를 초래 할 수 있 습 니 다.바 인 딩Watcher
이 없 으 면 여기까지 올 수 있 지만 수집 과정 에 의존 하지 않 으 면 하위 구성 요 소 를 업데이트 할 수 없습니다.기음 기교
또 남 의 몸 을 빌 고 싶다 면,아 퉤,남 의 편 의 를 빌 고,또 좋 은 성능 을 원한 다 면 어 떡 하지?여기에 곡선 으로 나 라 를 구 하 는 방법 이 있다.
<template>
<Child v-bind="attrsCopy" />
</template>
<script>
import _ from 'lodash';
import Child from './Child';
export default {
name: 'Child',
components: {
Child,
},
data() {
return {
attrsCopy: {},
};
},
watch: {
$attrs: {
handler(newVal, value) {
if (!_.isEqual(newVal, value)) {
this.attrsCopy = _.cloneDeep(newVal);
}
},
immediate: true,
},
},
};
</script>
총결산지금까지 우 리 는
v-bind="$attrs"
데이터 가 변화 가 없 지만 하위 구성 요 소 를 업데이트 시 키 는 원인 을 분 석 했 습 니 다.소스 코드 에 다음 과 같은 말 이 있 습 니 다.// $attrs & $listeners are exposed for easier HOC creation. // they need to be reactive so that HOCs using them are always updated
처음에 이런 디자인 의 목적 은
$attrs
고급 구성 요 소 를 더욱 잘 만 들 고 사용 하기 위해 서 였 다.HOC
구성 요 소 는 항상 데이터 변화 에 반응 하지만 실제 과정 에서HOC
와 부작용 이 생 겼 다.이 두 가지 사용 에 대해 데이터 가 빈번하게 변화 하지 않 을 때 사용 하거나 위의 기 음 기 교 를 사용 하 는 것 을 권장 했다.그리고..........................................................................Vue 가 왜$attrs 와$listeners 를 신중하게 사용 하 는 지 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.Vue$attrs 와$listeners 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 부 탁 드 리 겠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Vue Render 함수로 DOM 노드 코드 인스턴스 만들기render에서createElement 함수를 사용하여 DOM 노드를 만드는 것은 직관적이지 않지만 일부 독립 구성 요소의 디자인에서 특수한 수요를 충족시킬 수 있습니다.간단한 렌더링 예는 다음과 같습니다. 또한 v...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.