其他分享
首页 > 其他分享> > 实现自定义react hooks

实现自定义react hooks

作者:互联网

1:实现简版的 useState

每次调用顺序索引必须一样
返回初始状态变量,和更改状态方法
调用更改状态方法,更新状态并重新渲染
let lastStates = []
let index;
function useState(initValue) {
  let state = lastStates[index] || initValue;
  let currIndex = index;
  let setState = (newState) => {
    lastStates[currIndex] = newState;
    render();
  }
  index++
  return [state,setState]
}


2:实现简版的 useMemo
如果有dependencies未变化,返回上次对象的值
如果dependencies有变化,执行callback,返回新对象
let lastMemo
let lastMemoDependencies
function useMemo(callback,dependencies) {
  if (!lastMemo) {
    lastMemo = callback();
    lastMemoDependencies = dependencies;
   }
  else {
    let changed = !dependencies.every((item, idx) => item === lastMemoDependencies[idx])
    if (changed) {
      lastMemo = callback();
      lastMemoDependencies = dependencies;
    }
  }
  return lastMemo;
}

3:实现简版的 useCallback
如果有dependencies未变化,返回上次callback
如果dependencies有变化,返回新的callback
let lastCallback
let lastCallbackDependencies
function useCallback(callback,dependencies) {
  if (!lastCallback) {
    lastCallback = callback;
    lastCallbackDependencies = dependencies;
   }
  else {
    let changed = !dependencies.every((item, idx) => item === lastCallbackDependencies[idx])
    if (changed) {
      lastCallback = callback;
      lastCallbackDependencies = dependencies;
    }
  }
  return lastCallback;
}

4:实现简版的 useReducer
传入reducer,
返回状态和dispatch函数

let lastState
function useReducer(reducer, initValue) {
  lastState=lastState || initValue;
  let dispatch = function (action) {
    lastState= reducer(lastState, action);
    render();
  }
  return [lastState,dispatch]
}

5:实现简版的 useContext
共享变量

let Context = React.createContext();
function useContext(Context) {
  console.log('Context',Context);
  return Context._currentValue
}
此处Provider组件可以共享变量,useContext可以拿到对应的变量数据,在Counter组件中就可以使用useContext获取变量
<Context.Provider value={{ state, setState }}>
        <Counter></Counter>
</Context.Provider>


6:实现简版的 useEffect

浏览器事件环:
1)执行脚本代码(宏任务队列中取出)
2)进入主执行栈,依次执行
3)如遇到setTimeout,ajax,event, 把对应的回调放入宏任务队列, 宏任务队列在页面渲染之后执行
4)如遇到Promise, 把对应的回调放入微任务队列, 在页面渲染之前执行,所以任务会阻碍页面的渲染
5)显示器刷新率是60HZ, 每秒钟刷新60次, 也是就是16.67毫秒刷新一次



//在浏览器渲染后执行,不会阻塞浏览器运行
let lastDependencies
function useEffect(callback,dependencies) {
  if (!lastDependencies) {
    lastDependencies = dependencies;
    setTimeout(() => {
      callback();
    }, 0);
   }
  else {
    let changed = !dependencies.every((item, idx) => item === lastDependencies[idx])
    if (changed) {
      lastDependencies = dependencies;
      callback();
    }
  }
}



//在浏览器渲染前执行,会阻塞浏览器运行
let lastLayOutDependencies
function useLayoutEffect(callback,dependencies) {
  if (!lastLayOutDependencies) {
    lastLayOutDependencies = dependencies;
    queueMicrotask(callback);
    // Promise.resolve().then(callback)
   }
  else {
    let changed = !dependencies.every((item, idx) => item === lastLayOutDependencies[idx])
    if (changed) {
      lastLayOutDependencies = dependencies;
      queueMicrotask(callback);
      // Promise.resolve().then(callback)
    }
  }
}





<!DOCTYPE html>
<html lang="en">
    <script>
        // display Hello World and then page stuck because the infinite loop
        setTimeout(() => {
            while (true) {}
            console.log('setTimeout');
            document.body.style.backgroundColor = '#ccc';
        }, 0);
        // no Hello World display and page stuck because the infinite loop
        Promise.resolve().then(() => {
            while (true) {}
            console.log('Promise');
        });
    </script>

    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        Hello World
    </body>
</html>

 

 

标签:idx,自定义,item,hooks,changed,react,callback,dependencies,let
来源: https://www.cnblogs.com/dming4/p/16519782.html