diff --git a/packages/hooks/use-attrs/index.ts b/packages/hooks/use-attrs/index.ts index 0e561f73ce..2b86602517 100644 --- a/packages/hooks/use-attrs/index.ts +++ b/packages/hooks/use-attrs/index.ts @@ -1,5 +1,7 @@ -import { getCurrentInstance, reactive, shallowRef, watchEffect } from 'vue' -import { entries } from '@element-plus/utils/util' +import { getCurrentInstance, computed } from 'vue' +import { warn } from '@element-plus/utils/error' + +import type { ComputedRef } from 'vue' interface Params { excludeListeners?: boolean @@ -9,29 +11,26 @@ interface Params { const DEFAULT_EXCLUDE_KEYS = ['class', 'style'] const LISTENER_PREFIX = /^on[A-Z]/ -export default (params: Params = {}) => { +export default (params: Params = {}): ComputedRef> => { const { excludeListeners = false, excludeKeys = [] } = params - const instance = getCurrentInstance() - const attrs = shallowRef({}) const allExcludeKeys = excludeKeys.concat(DEFAULT_EXCLUDE_KEYS) - // Since attrs are not reactive, make it reactive instead of doing in `onUpdated` hook for better performance - instance.attrs = reactive(instance.attrs) + const instance = getCurrentInstance() + if (!instance) { + warn( + 'use-attrs', + 'getCurrentInstance() returned null. useAttrs() must be called at the top of a setup function' + ) + return computed(() => ({})) + } - watchEffect(() => { - const res = entries(instance.attrs).reduce((acm, [key, val]) => { - if ( - !allExcludeKeys.includes(key) && - !(excludeListeners && LISTENER_PREFIX.test(key)) - ) { - acm[key] = val - } - - return acm - }, {}) - - attrs.value = res - }) - - return attrs + return computed(() => + Object.fromEntries( + Object.entries(instance.proxy?.$attrs).filter( + ([key]) => + !allExcludeKeys.includes(key) && + !(excludeListeners && LISTENER_PREFIX.test(key)) + ) + ) + ) }