function resolveDispatcher() {
const dispatcher = ReactCurrentDispatcher.current;
invariant(
dispatcher !== null,
'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +
' one of the following reasons:\n' +
'1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
'2. You might be breaking the Rules of Hooks\n' +
'3. You might have more than one copy of React in the same app\n' +
'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.',
return dispatcher;
import type {Dispatcher} from 'react-reconciler/src/ReactInternalTypes';
* Keeps track of the current dispatcher.
const ReactCurrentDispatcher = {
* @internal
* @type {ReactComponent}
current: (null: null | Dispatcher),
export default ReactCurrentDispatcher;
React provides a declarative API so that you don’t have to worry about exactly what changes on every update. This makes writing applications a lot easier, but it might not be obvious how this is implemented within React. This article explains the choices we made in React’s “diffing” algorithm so that component updates are predictable while being fast enough for high-performance apps.
data 是上面提到的 reactive data 啦。computed 跟一般拿 data 內容當作參數的函式沒兩樣,只是宣告在這邊方便多加快取功能
Instead of a computed property, we can define the same function as a method. For the end result, the two approaches are indeed exactly the same. However, the difference is that computed properties are cached based on their reactive dependencies. A computed property will only re-evaluate when some of its reactive dependencies have changed.
至於原始碼的話大概就是
/src/core/instance/state.js
export function initState (vm: Component) {
vm._watchers = []
const opts = vm.$options
if (opts.props) initProps(vm, opts.props)
if (opts.methods) initMethods(vm, opts.methods)
if (opts.data) {
initData(vm)
} else {
observe(vm._data = {}, true /* asRootData */)
if (opts.computed) initComputed(vm, opts.computed)
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch)
function initData (vm: Component) {
let data = vm.$options.data
data = vm._data = typeof data === 'function'
? getData(data, vm)
: data || {}
if (!isPlainObject(data)) {
data = {}
process.env.NODE_ENV !== 'production' && warn(
'data functions should return an object:\n' +
'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
// proxy data on instance
const keys = Object.keys(data)
const props = vm.$options.props
const methods = vm.$options.methods
let i = keys.length
while (i--) {
const key = keys[i]
if (process.env.NODE_ENV !== 'production') {
if (methods && hasOwn(methods, key)) {
warn(
`Method "${key}" has already been defined as a data property.`,
if (props && hasOwn(props, key)) {
process.env.NODE_ENV !== 'production' && warn(
`The data property "${key}" is already declared as a prop. ` +
`Use prop default value instead.`,
} else if (!isReserved(key)) {
proxy(vm, `_data`, key)
// observe data
observe(data, true /* asRootData */)
這附近吧!有去找物件的 data 跟 computed 屬性,還有 watch 屬性之類的,找出來放進 reactivity data 模型裡面,準備後面的互動吧!
export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
export function reactive(target: object) {
// if trying to observe a readonly proxy, return the readonly version.
if (target && (target as Target)[ReactiveFlags.IS_READONLY]) {
return target
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers
前面一直說 value function 算是說錯了,其中一個 RFC 是叫 value 但後面又刪掉改名稱為 reactive 囉。
最後會使用 createReactiveObject 來實作 reactive data 哦
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>
if (!isObject(target)) {
if (__DEV__) {
console.warn(`value cannot be made reactive: ${String(target)}`)
return target
// target is already a Proxy, return it.
// exception: calling readonly() on a reactive object
target[ReactiveFlags.RAW] &&
!(isReadonly && target[ReactiveFlags.IS_REACTIVE])
return target
// target already has corresponding Proxy
hasOwn(target, isReadonly ? ReactiveFlags.READONLY : ReactiveFlags.REACTIVE)
return isReadonly
? target[ReactiveFlags.READONLY]
: target[ReactiveFlags.REACTIVE]
// only a whitelist of value types can be observed.
if (!canObserve(target)) {
return target
const observed = new Proxy(
target,
collectionTypes.has(target.constructor) ? collectionHandlers : baseHandlers
target,
isReadonly ? ReactiveFlags.READONLY : ReactiveFlags.REACTIVE,
observed
return observed
終於看到 new Proxy 關鍵字囉!可見 vue 3 背後有使用原生的 Proxy 功能來實作哦!