这里波及整个hooks的一个入口函数:renderWithHooks
这个函数中只截取跟hookstype无关的局部:

{    if (current !== null && current.memoizedState !== null) {      // 如果是更新中,那么用HooksDispatcherOnUpdateInDEV      ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV;    } else if (hookTypesDev !== null) {      // This dispatcher handles an edge case where a component is updating,      // but no stateful hooks have been used.      // We want to match the production code behavior (which will use HooksDispatcherOnMount),      // but with the extra DEV validation to ensure hooks ordering hasn't changed.      // This dispatcher does that.            // 如果是hookTypesDev不为空,那么用HooksDispatcherOnMountWithHookTypesInDEV      ReactCurrentDispatcher$1.current = HooksDispatcherOnMountWithHookTypesInDEV;    } else {      // 默认状况:用HooksDispatcherOnMountInDEV,这也是个别的初始化的时候用的。      ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV;    }  }

接下来有7个对象:
HooksDispatcherOnMountInDEV
HooksDispatcherOnMountWithHookTypesInDEV
HooksDispatcherOnUpdateInDEV
HooksDispatcherOnRerenderInDEV
InvalidNestedHooksDispatcherOnMountInDEV
InvalidNestedHooksDispatcherOnUpdateInDEV
InvalidNestedHooksDispatcherOnRerenderInDEV
这7个对象里都实现了一整套的useMemo、useCallback等,一整套的hooks。
然而构造都很类似,咱们用useState来比照每个的不同。

先看HooksDispatcherOnMountInDEV

useState: function (initialState) {    // 扭转以后的hookname为useState      currentHookNameInDev = 'useState';      // 把hookname放进一个数组hookTypesDev里      mountHookTypesDev();      // 上面两行是迭代dispatch的。等于是把以后的存到prev里,而后让以后变成InvalidNestedHooksDispatcherOnMountInDEV      var prevDispatcher = ReactCurrentDispatcher$1.current;      ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;      try {        return mountState(initialState);      } finally {        // 必然执行,将prev放到以后,因为不能再应用InvalidNestedHooksDispatcherOnMountInDEV了。        // 前面会说为什么不能再应用InvalidNestedHooksDispatcherOnMountInDEV        ReactCurrentDispatcher$1.current = prevDispatcher;      }    },

附:
mountHookTypesDev办法,很简略,就是把以后的hookname放进一个数组hookTypesDev里。

function mountHookTypesDev() {  {    var hookName = currentHookNameInDev;    if (hookTypesDev === null) {      hookTypesDev = [hookName];    } else {      hookTypesDev.push(hookName);    }  }}

再来看HooksDispatcherOnMountWithHookTypesInDEV
和HooksDispatcherOnMountInDEV只有一句的区别

useState: function (initialState) {      currentHookNameInDev = 'useState';      // 和HooksDispatcherOnMountInDEV只有这一行不同,这里的更新。其余齐全一样。      updateHookTypesDev();      var prevDispatcher = ReactCurrentDispatcher$1.current;      // 这里和HooksDispatcherOnMountInDEV一样。      ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;      try {        return mountState(initialState);      } finally {        ReactCurrentDispatcher$1.current = prevDispatcher;      }    },

再看HooksDispatcherOnUpdateInDEV
和HooksDispatcherOnMountWithHookTypesInDEV只有一句的区别

useState: function (initialState) {      currentHookNameInDev = 'useState';      updateHookTypesDev();      var prevDispatcher = ReactCurrentDispatcher$1.current;      // 这里也是有区别的。但不太重要      ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;      try {        // 和HooksDispatcherOnMountWithHookTypesInDEV只有这一句的区别        return updateState(initialState);      } finally {        ReactCurrentDispatcher$1.current = prevDispatcher;      }    },

再看HooksDispatcherOnRerenderInDEV
这里须要阐明,HooksDispatcherOnRerenderInDEV在renderWithHooks办法中是在前面赋值的,能够了解为是render是执行的。
和HooksDispatcherOnUpdateInDEV比,又只有一句的区别

useState: function (initialState) {      currentHookNameInDev = 'useState';      updateHookTypesDev();      var prevDispatcher = ReactCurrentDispatcher$1.current;      // 这里也是有区别的。但不太重要      ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnRerenderInDEV;      try {        // 只有这一句的区别          return rerenderState(initialState);      } finally {        ReactCurrentDispatcher$1.current = prevDispatcher;      }    },

InvalidNested的mount、update、render
这三个一块说。
InvalidNestedHooksDispatcherOnMountInDEV

useState: function (initialState) {      currentHookNameInDev = 'useState';      // 都减少了这行      warnInvalidHookAccess();      mountHookTypesDev();      var prevDispatcher = ReactCurrentDispatcher$1.current;      // 这行略有不同      ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;      try {        return mountState(initialState);      } finally {        ReactCurrentDispatcher$1.current = prevDispatcher;      }    },

InvalidNestedHooksDispatcherOnUpdateInDEV:

useState: function (initialState) {      currentHookNameInDev = 'useState';      // 都减少了这行      warnInvalidHookAccess();      updateHookTypesDev();      var prevDispatcher = ReactCurrentDispatcher$1.current;      // 这行略有不同,留神这里是update,不是render      ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;      try {        return rerenderState(initialState);      } finally {        ReactCurrentDispatcher$1.current = prevDispatcher;      }    },

这三局部,都是为了warnInvalidHookAccess这个正告代码:
不要在useEffect、useMemo里创立hooks,你只能在顶层的react组件中创立hooks。
源码如下:

var warnInvalidHookAccess = function () {    error('Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' + 'You can only call Hooks at the top level of your React function. ' + 'For more information, see ' + 'https://reactjs.org/link/rules-of-hooks');  };

总结

能够了解,每一个都是,如果在mountState、updateState、renderState区间,又做了mount、update、render的话,就会报正告,同时下一次还是在InvalidNested。
这个性能在state里,一个比拟典型的场景是当setState办法里又执行了hooks办法,就会报error。
或者在useMemo、useEffect办法里创立hooks,也会报error。