background

Hooks are not to be confused with Vue’s Lifecycle hooks. Hooks were introduced in V16.7.0-alpha and Vue released its proof-of-concept a few days later. Hook is a proposed new feature in React that allows developers to use states and other React functions without writing classes.

define

Hooks primarily provide a more explicit way to reuse schemas — avoid rewriting components themselves and allow different parts of stateful logic to work seamlessly together.

Stateless functional components are also very popular, but because they can only be rendered purely, their use is limited to presentation tasks.

Hooks solve these problems by allowing us to define a component’s stateful logic using function calls. These function calls become more combinatorial, reusable, and allow us to access and maintain state while working with functional components.

Why are Hooks needed in Vue?

What Hooks must provide in Vue. This seems like a problem that doesn’t need to be solved. After all, classes are not the primary pattern used by Vue. Vue provides stateless functional components (if you need them), but why do we need to carry state in functional components? We have mixins for composing the same logic that can be reused across multiple components. Problem solved.

The source code interpretation

The h function is createElement, which produces a VNode, or HTML DOM node

CreateElement (h) is a function in vuejs. This function generates a VNode. Once the render function gets the VNode, it returns to the mount function of vue. js, renders it as a real DOM node, and mounts it to the root node.

1. What does useEffect do?

By using this Hook, the React component is told what it needs to do after rendering. React will remember the function passed (calling the function “effect”) and call the function after performing a DOM update. In this effect, the main function is still to set document.title, but it can also perform data fetching or call other imperative apis.

IsMounting: Indicates whether the render is the first time

Several local variables declared on vue Options:

  • _state: Places responsive data
  • _refsStore: Places non-responsive data and returns a reference type
  • _effectStore: stores side effect logic and cleanup logic
  • _computedStore: stores computing attributes

Vue-hooks exposes a hooks function that allows developers to mix internal logic into all child components after the vue.use (hooks) entry. This allows us to use hooks in the SFC component.

One of the main differences between Hooks and mixins is that Hooks actually pass each other values. _vNode is initialized to null. In the Mounted phase, V-DOM Hooks are assigned to the current component. Rather than forcing split based on a lifecycle approach. SeEffect provides functionality similar to Mounted in componentDidMount and other lifecycle hooks

The useData useState method of hooks can only be used in hooks or widthHooks

The data in hooks is in the order in which useState appears

With withHooks, we can do what hooks do, but sacrifice a lot of vue features like props, attrs, Components, etc.

The concept of “Effect” is called “side Effect”. Refers to the asynchronous request of related remote data, event binding, DOM change, etc., when state changes; These actions are called “side effects” because they either cause changes to other components or are not immediately complete during the rendering cycle.

REACT useEffect Can perform different types of side effects after the component render. Some effects may need to be cleaned up, so you can return a function in effect:

React www.ptbird.cn/react-hoot-… Vue www.jianshu.com/p/f1e6597b1… Jane books www.sohu.com/a/321909448… Precision vue – hooks juejin. Cn/post / 684490… The nuggets mp.weixin.qq.com/s/p2f3jsko9… Cloud front 1 byte. IO/react – hooks… The react blog.csdn.net/liuyingv8/a… The react 30 minutes

Disadvantages of traditional VUE components

  • Cross-component code is difficult to reuse
  • Large components, difficult to maintain, granularity is not easy to control, fine granularity partition, component nesting level is too deep – affecting performance
  • Class component, this is uncontrollable, logically scattered, not easy to understand
  • Mixins have the side effects of nested logic, unknown data sources, and non-consumption of each other

This is the current vue instance. Assign this to currentInstance and _effectStore to the current Vue instance

CurrentInstance is the current VUE instance, and this is the proxy object

– How do hooks fix minix

  • Data consumption hooks can access the data of the current VUE instance, and can consume each other
  • Which is the source of the data. hooks are called manually, so it is clear where the source is

BeforeMount triggers render function, registers event, and nulfies current variable after currentInstance is assigned and set to null

5. In reder, h is used twice in foo to convert JSX into an option object, and the second h function is used to convert an option object into a virtual DOM

6. Incrementing the id to get a new value each time? Vue -hooks replace retrieving and setting data with ids, access ids to get mapped values, data in each VUE instance has a fixed ID

$on(‘hook: Mounted ‘) emit emit

8, it is unknown whether hooks live data or computed,props can be accessed, and whether they can be defined

What’s the problem with mixins? Mixins cannot consume each other and use state, but hooks can. What is the use of hooks?

9. When will multiple renders be made

Which life cycle do the hooks execute beforeMount

11. Cannot be placed in conditions or loops

  • The number of calls to useState() must be the same.
  • UseState () is called in the same order as each state.

12, what are custom hooks, which solve what problems, how to use them, and what problems do they have?

13, instead of using vue-hooks globally, can you import only the corresponding hooks file? No, withHooks still return options as a vue Component configuration item. Subsequent hooks related properties are mounted on locally supplied options.

14, cannot declare the same attribute _state, will be overwritten

Vue -hooks fixes the problem

  • Realize the function of mixins, and solve two problems of mixins
    • Allows states to be passed to each other
    • Specifies where the logic comes from. Use Hooks, the return value of the function records the consumed value.
  • Vue-hooks are the latest attempt to simplify component definitions and reuse state logic, and combine the characteristics of vue instances to provide hooks that are applicable

This in rest.js is the current vue instance

React-hooks only appear at the top level of a function scope, not in conditional statements, loop statements, or nested functions.

conclusion

WithHooks returns a wrapped Vue instance configuration

Hooks work as mixins, injecting two lifecycles

A Vue instance where Hooks are in effect is logged using the module-local variable currentInstance

use

WithHooks provides hooks+VNode for the Vue component as follows:

WithHooks returns a wrapped Vue instance configuration

  • Vue type hooks
  • Usage in plain Vue components

If useState is wrapped in condition, the subscripts may not be correct each time it is executed, causing the setter exported by useState to update the wrong data.

The source code interpretation

letCurrentInstance = null // Cache the current VUE instancelet isMounting = false// render is the first renderletCallIndex = 0 // Index of the current data. When mounting attributes to options, use callIndex as the unique index identifierfunction ensureCurrentInstance() {// Whether there is an instanceif(! CurrentInstance) {// Invalid hook call: hook throw new Error(' Invalid hooks call: hooks can only be called in a function passed to Withhooksin a function passed to withHooks.`
    )
  }
}

export function useState(initial) {
  ensureCurrentInstance()
  const id = ++callIndex
  const state = currentInstance.$dataConst updater = newValue => {state[id] = newValue}if (isMounting) {
    currentInstance.$set(state, id, initial)} // The next render process will not be used again$setInitialize thereturn[state[id], updater]} // Take care of the side effects and clean up the logic. // These operations may cause side effects such as the need to clear DOM listeners, clear references, etc.export functionUseEffect (rawEffect, deps) {ensureCurrentInstance() const id = ++callIndex; // In the Mounted phase, call the side effect function once and save the return value as the cleanup logic. // Also determine whether to call the side effect function again in the updated phase based on the dependency.if (isMounting) {
    const cleanup = () => {
      const { current } = cleanup
      if (current) {
        current()
        cleanup.current = null
      }
    }
    const effect = function() {
      const { current } = effect
      ifCurrent = current. Call (this) effect. Current = null}} CurrentInstance = rawEffect currentInstance._effectStore[id] = {effect, cleanup, deps } // \vue-dev\src\core\instance\lifecycle.js currentInstance.$on('hook:mounted', effect)
    currentInstance.$on('hook:destroyed', cleanup)
    if(! deps || deps.length > 0) { currentInstance.$on('hook:updated', effect)
    }
  } else{// If it is not the first time, the deps dependency is used to determine whether the side effect function needs to be called again. // If it needs to be executed again, the last side effect function should be cleared first, and the current side effect function should point to the latest side effect logic. const record = currentInstance._effectStore[id] const { effect, cleanup, deps: prevDeps = [] } = record record.deps = depsif(! deps || deps.some((d, i) => d ! == prevDeps[I])) {cleanup() effect.current = rawEffect}}} // f initialization returns a reference with current pointing to the initialized valueexport function useRef(initial) {
  ensureCurrentInstance()
  const id = ++callIndex
  const { _refsStore: refs } = currentInstance
  returnisMounting ? Refs [id] = {current: initial}) : refs[id]} // Mount a reactive data, but no updater is providedexport function useData(initial) {
  const id = ++callIndex
  const state = currentInstance.$data._state
  if (isMounting) {
    currentInstance.$set(state, id, initial)
  }
  returnState [id]} // useEffect When [] is passed, the useEffect function is called only in the Mounted phase.export functionUseMounted (fn) {useEffect(fn, [])} useMounted(fn) {useEffect(fn, [])}export functionUseDestroyed (fn) {useEffect(() => fn, [])} // Use useRef to declare a persistent variable to skip the mounted phase.export function useUpdated(fn, deps) {
  const isMount = useRef(true)
  useEffect(() => {
    if (isMount.current) {
      isMount.current = false
    } else {
      return fn()
    }
  }, deps)
}

export functionUseWatch (getter, cb, options) {ensureCurrentInstance() // Adds a first render judgment to prevent re-render from generating extra Watcher observers.if (isMounting) {
    currentInstance.$watch(getter, cb, options)
  }
}

export function useComputed(getter) {
  ensureCurrentInstance()
  const id = ++callIndex
  const store = currentInstance._computedStore
  if(isMounting) {// The dependency values are calculated and cached store[id] = getter() // call$watchTo observe the dependency property changes and update the corresponding cached value. currentInstance.$watch(getter, val => {
      store[id] = val
    }, { sync: true})}return store[id]
}

export function withHooks(render) {
  return {
    data() {
      return{_state: {} // can not declare the same attribute _state, will be overridden}},created() { this._effectStore = {} this._refsStore = {} this._computedStore = {} }, Render (h) {callIndex = 0 currentInstance = this // Add isMounting =! This. _vnode // _vnode is initialized to null. In the Mounted stage, the value is assigned to the V-DOM of the component. Render (h, this) const ret = render(h, this)$attrs, this.$propsAttrs and attrs are passed in$propsAs an input parameter and currentInstance = NULL after rendering the current component // reset the global variable for rendering the next component.return ret
    }
  }
}

export functionHooks (Vue) {vue.mixin ({// switch in two life cyclesbeforeCreate() {
      const { hooks, data } = this.$options
      if (hooks) {
        this._effectStore = {}
        this._refsStore = {}
        this._computedStore = {}
        this.$options.data = function() { const ret = data ? Data.call (this) : {} ret._state = {} // Reset the _state propertyreturn ret
        }
      }
    },
    beforeMount() {
      const { hooks, render } = this.$options
      if (hooks && render) {
        this.$options.render = function(h) { callIndex = 0 currentInstance = this isMounting = ! _vnode // _vnode is initialized to null, and in the Mounted phase is assigned to the V-dom of the current component const hookProps = hooks(this.$props// Call the hooks method, which willreturnObject.assign(this._self, hookProps) const ret = render. Call (this, h) currentInstance = nullreturn ret
        }
      }
    }
  })
}

Copy the code