За последние два дня Дашуай*, Дашенг и дядя Ран рассказали о мотивации дизайна и концепции API композиции.
Эта анимация Vue3, которая работала всю ночь, хороша, но слишком короткая.
Занят всю ночь, используя CompositionAPI, чтобы покорить прибамбасы продакт-девушек
Я сделал ночь анимации, просто чтобы все лучше поняли Composition API Vue3.
Еще один глубокий анализ моего принципа композиции
Lightning Five Whip: подробный анализ принципов Composition API
Это действительно щекочет всех, и многие люди начинают что-то писать, а затем некоторые вопросы по применению:
- нет
thisТеперь, как мне получить экземпляр компонента? - нет
thisТеперь, как отправлять пользовательские события? - как я могу
reactiveа такжеrefвыбирать между? - Что делать, если функция настройки слишком длинная?
- Почему мой ресурс не отвечает?
-
watchEffectа такжеwatchКакая разница? - Можно ли написать несколько хуков жизненного цикла? Каков порядок?
Как получить экземпляр компонента?
Все мы знаем, что составной API можно использовать и дружить с опциями API, как в следующем примере:
const { createApp } = Vue
createApp({
data() {
return {
foo: 'foo'
}
},
setup() {
// 没有this,我该如何获取data中的foo和methods中的bar哪?
return { }
},
methods: {
bar() {
console.log('我是bar方法');
}
},
}).mount('#app')
Но в настройкеthisнаправлениеwindow, в документе состава не упоминается, как получить экземпляр компонента, что действительно поставило в тупик многих мелких партнеров.Естественно, есть методы: мы можем передатьgetCurrentInstance()Этот интерфейс получает экземпляр компонента:
setup() {
// getCurrentInstance()可以获取组件实例
const instance = getCurrentInstance()
console.log(instance);
onMounted(()=>{
// 组件实例的上下文才是我们熟悉的this
console.log(instance.ctx.foo); // 'foo'
console.log(instance.ctx.bar()); // '我是bar方法'
})
return {}
},
Но вскоре мы снова запутались, этот экземпляр компонента такой же, как тот, с которым мы были знакомы раньшеthisНе то же самое, прямой доступthis.fooВсе еще не могу найти данные.
Экземпляр компонента Vue3 в следующей структуре, различные вариантыthisв реальностиctxилиproxy
Ямы конечно есть еще, вы внимательно за этим наблюдаетеctx, обнаружил, что это не объект Proxy, то есть этот Xiongtai имеет только значение, но не отзывчивость, поэтому, если вы хотите использовать адаптивную функцию, вы должны использоватьproxyЭто свойство возвращает объект контекста. Если вам нужны только данные, на картинке выше их нет.dataЭто также тип прокси.
setup() {
const { proxy, data } = getCurrentInstance()
// 想要利用响应能力,就要使用proxy这个上下文
watchEffect(() => {
console.log(proxy.foo) // foo变化会有输出
console.log(data.foo) // foo变化会有输出
})
},
Наконец, все также должны учитывать, что время выполнения setup() очень раннее, даже раньше, чем создано, поэтому доступ к foo и bar действительно недоступен, если они специально не помещены в onMounted.
setup() {
const instance = getCurrentInstance()
console.log(instance.ctx.foo); // undefined
console.log(instance.ctx.bar()); // undefined
},
Как отправлять пользовательские события?
После того, как вдруг этого нет, кажется, что вдруг жизнь не может о себе позаботиться и больше не может быть использованаthis.$emit()Отправка события.
На самом деле события можно отправлять через экземпляры компонентов, например:
setup() {
getCurrentInstance().emit('ooxx')
}
Но это более хлопотно, поэтому мы используемsetupВторой параметр функции:
setup(props, ctx) {
ctx.emit('ooxx')
}
Конечно, удобнее деконструировать emit напрямую:
setup(props, { emit }) {
emit('ooxx')
}
как я могуreactiveа такжеrefвыбирать между?
композиция-api представляет независимые методы, реагирующие на данныеreactive, он может выполнять реактивную обработку входящих объектов:
const state = reactive({
foo: 'foo',
})
watchEffect(() => {
console.log(state.foo)
})
state.foo = 'foooooo' // 输出 'foooooo'
Этот метод аналогичен тому, что мы установилиdataвариант, который может решить большинство наших потребностей. Но есть и следующие проблемы:
-
Когда мы экспортируем состояние напрямую, нам нужно префикс состояния с шаблоном
setup() { const state = reactive({}) return { state } }<div>{{ state.foo }}</div>Чтобы решить эту проблему, необходимо ввести toRefs.
setup() { const state = reactive({}) return { ...toRefs(state) } }<div>{{ foo }}</div>Маленькие друзья снова в замешательстве, что такое Рефы? Почему бы просто не расшириться напрямую?
-
Использование reactive() для одного значения избыточно
Так что естьRefконцепция, обернув единственное значениеRefобъект, чтобы его можно было реактивно проксировать
setup() {
const foo = ref('foo')
return { foo }
}
Префикс также может быть опущен при использовании в шаблоне,toRefsЭто нужно использовать для преобразования значения, соответствующего каждому ключу прокси-объекта, возвращаемого reactive(), в Ref.
<div>{{ foo }}</div>
Но у объектов Ref также есть побочные эффекты:
-
Изменение этого значения в JS требует дополнительных
value:setup() { const foo = ref('foo') setTimeout(() => { // 额外的value让人恼火 foo.value++ }, 1000) return { foo } } -
Дополнительная умственная нагрузка: действительно ли ценность?
Ref, я должен добавить.value?setup(props) { const foo = props.foo // foo是Proxy还是Ref? // 编写`watch`方法的时候写法完全不同 // Ref可以被直接watch watch(foo, () => {}) // Proxy则需要写成函数形式 watch(() => foo.bar, () => {}) }
После сравнения мы обнаружили, что есть некоторые проблемы.Давайте обсудим выбор между ними:
-
Если это одно значение, рекомендуется ссылаться, даже если это объект с одним значением.
const counterRef = ref(1) const usersRef = ref(['tom', 'jerry']) -
Деловая озабоченность имеет несколько значений, рекомендуется быть реактивным
const mouse = reactive({ x: 0, y: 0 }) -
уменьшать
RefМетод умственной нагрузки: используйте такие инструменты, как unref, isRef, isProxy и т. д., и используйте некоторые соглашения об именах.setup(props) { const foo = unref(props.foo) // foo是我们要的值 // 等效于 const foo = isRef(props.foo) ? props.foo.value : props.foo }
Что делать, если функция настройки слишком длинная?
Хотя хорошо сфокусировать фокус, вот так:
Но это неизбежно слишком долго (почему слишком долго проблема?), в это время вы можете начать разделение функций
setup(){
let { val, todos, addTodo } = useTodo()
let {count,double,add} = useCounter()
let {x, double:doubleX} = useMouse()
return {
val, todos, addTodo,
count,double,add,
x,doubleX
}
}
Контекст возврата слишком длинный, мы можем использовать vue3setup scriptфункция, конфигурация настройки также оптимизируется, и функция экспортируется один раз
<script setup>
import useCounter from './counter'
import useMouse from './mouse'
import useTodo from './todos'
let { val, todos, addTodo } = useTodo()
export {val, todos, addTodo}
let {count,double,add} = useCounter()
export {count,double,add}
let {x, double:doubleX} = useMouse()
export {x,doubleX}
</script>
Почему мой ресурс не отвечает?
Следующий код — это то, что могут написать ваши друзья:
setup({ foo, bar }) {
watchEffect(() => {
console.log(foo, bar) // foo,bar发生变化,也不会有输出
})
}
props — это прокси-объект, и он теряет свою отзывчивость при прямой деконструкции, поэтому будьте осторожны с реквизитами и не можете разделяться на каждом шагу.
setup(props) {
watchEffect(() => {
console.log(props.foo, props.bar) // foo,bar发生变化,会有输出
})
}
Если вы действительно хотите разделить его, это зависит от того, какая поза вам нравится.
setup(props) {
const { foo, bar } = toRefs(props)
watchEffect(() => {
console.log(foo.value, bar.value) // foo,bar发生变化,会有输出
})
}
watchEffectа такжеwatchКакая разница?
Эти два метода очень похожи в том, что они оба наблюдают реактивные данные и выполняют функции побочных эффектов при внесении изменений, но различия заключаются в следующем:
-
часы должны явно указать цель мониторинга
watch(() => state.counter, (val, prevVal) => {})watchEffect не требуется
watchEffect(() => { console.log(state.counter) }) -
watch может получить значение до и после изменения
-
смотреть лениво, это эквивалентно vue2
this.$watch(), watchEffect нужно выполнить немедленно, чтобы собрать зависимости
Теперь вы знаете, как их выбирать?
Можно ли написать несколько хуков жизненного цикла?
Конечно, вы можете написать больше одного, и в итоге они будут выполняться в порядке регистрации:
setup() {
onMounted(() => {})
onMounted(() => {})
onMounted(() => {})
}
Он даже может разделить несколько идентичных хуков жизненного цикла на независимые функции, что довольно красиво.
function fun1() {
// 这里可以用onMounted执行代码
onMounted(() => {})
}
function fun2() {
// 这里还可以用onMounted执行代码
onMounted(() => {})
}
setup() {
fun1()
fun2()
onMounted(() => {})
}
Давайте сначала поговорим о практическом обмене композицией. Есть ли вопросы, которые не касаются? Вы можете оставить мне сообщение в разделе комментариев, чтобы обсудить.
Если вам нравится смотреть обучающие видео, добро пожаловать вЯнцуньМагазин вокруг.
Последний лайк это еще волна запросов, может тот что перед экраномБольшое красивое соотношениеа такжеПрекрасныйПросто следуйте за ним! ! !
-
Это проект с открытым исходным кодом нашей команды.element3
-
Библиотека компонентов внешнего интерфейса, поддерживающая vue3.