手写React-hooks

76 阅读4分钟

useCallback

useCallback是用于创建缓存的回调函数的Hook。它接受一个回调函数和一个依赖数组,并返回一个被缓存的版本。当依赖数组发生变化时,useCallback会返回一个新的回调函数。

源码逻辑

// 导入状态和状态索引相关的变量和函数
import { hookStates, hookIndex, setHookStates, setHookIndexAdd } from './state';
​
// useCallback Hook
export function useCallback(callback, deps) {
  // 如果存在上一次的状态
  if (hookStates[hookIndex]) {
    const [lastCallback, lastDeps] = hookStates[hookIndex];
    // 判断依赖数组是否完全相等
    const same = deps.every((item, index) => item === lastDeps[index]);
    if (same) {
      // 如果相等,则直接返回上一次的回调函数
      setHookIndexAdd();
      return lastCallback;
    } else {
      // 如果不相等,则更新状态并返回新的回调函数
      setHookStates(setHookIndexAdd(), [callback, deps]);
      return callback;
    }
  } else {
    // 如果是第一次调用,则设置状态并返回回调函数
    setHookStates(setHookIndexAdd(), [callback, deps]);
    return callback;
  }
}
​

示例用法

const ExampleComponent = () => {
  const handleClick = useCallback(() => {
    console.log('Button clicked');
  }, []);
​
  return <button onClick={handleClick}>Click me</button>;
};

useMemo

useMemo用于创建缓存的值的Hook。它接受一个回调函数和一个依赖数组,并返回一个被缓存的值。当依赖数组发生变化时,useMemo会重新计算并返回新的值。

源码逻辑

  // 导入状态和状态索引相关的变量和函数
    import { hookStates, hookIndex, setHookStates, setHookIndexAdd } from './state';
    // useMemo Hook
    export function useMemo(factory, deps) {
      // 如果存在上一次的状态
      if (hookStates[hookIndex]) {
        let [lastMemo, lastDeps] = hookStates[hookIndex];
        // 判断依赖数组是否完全相等
        let same = deps.every((item, index) => item === lastDeps[index]);
        if (same) {
          // 如果相等,则直接返回上一次的缓存值
          setHookIndexAdd();
          return lastMemo;
        } else {
          // 如果不相等,则执行工厂函数创建新的缓存值
          let newMemo = factory();
          // 更新状态并返回新的缓存值
          setHookStates(setHookIndexAdd(), [newMemo, deps]);
          return newMemo;
        }
      } else {
        // 如果是第一次调用,则执行工厂函数创建新的缓存值
        let newMemo = factory();
        // 设置状态并返回新的缓存值
        setHookStates(setHookIndexAdd(), [newMemo, deps]);
        return newMemo;
      }
    }

示例用法

    const ExampleComponent = () => {
      const expensiveValue = useMemo(() => {
        // 执行一些昂贵的计算
        return computeExpensiveValue();
      }, []);
    ​
      return <div>{expensiveValue}</div>;
    };

useState

useState是用于在函数组件中添加状态的Hook。它接受一个初始状态,并返回一个由当前状态和更新状态的函数组成的数组。

源码逻辑

    // 导入状态和状态索引相关的变量和函数
    import { hookStates, hookIndex, setHookStates, setHookIndexAdd } from './state';
    ​
    // useState实现
    export const useState = (initialState, render) => {
      // 如果状态不存在,则设置初始状态
      hookStates[hookIndex] = hookStates[hookIndex] || initialState;
      const currentIndex = hookIndex;
      
      const setState = (newState) => {
        // 更新状态
        if (typeof newState === 'function') {
          // 如果新状态是一个函数,则调用它,并将当前状态作为参数传递
          setHookStates(currentIndex, newState(hookStates[currentIndex]));
        } else {
          // 如果新状态不是函数,则直接设置为新状态的值
          setHookStates(currentIndex, newState);
        }
        
        // 触发组件重新渲染
        render();
      };
    ​
      // 返回当前状态和设置状态的函数
      return [hookStates[setHookIndexAdd()], setState];
    }
    ​

示例用法

    const ExampleComponent = () => {
      const [count, setCount] = useState(0);
    ​
      const increment = () => {
        setCount(count + 1);
      };
    ​
      return (
        <div>
          <p>Count: {count}</p>
          <button onClick={increment}>Increment</button>
        </div>
      );
    };

useEffect

useEffect用于在函数组件中执行副作用操作的Hook。它接受一个副作用函数和一个依赖数组,并在每次渲染后执行该副作用函数。

源码逻辑

 // 导入状态和状态索引相关的变量和函数
    import { hookStates, hookIndex, setHookStates, setHookIndexAdd } from "./state";
    ​
    // useEffect实现
    export const useEffect = (callback, deps) => {
      // 如果存在上一次的状态
      if (hookStates[hookIndex]) {
        const [oldDestroy, lastDeps] = hookStates[hookIndex];
        // 判断依赖数组是否完全相等
        const same = deps.every((item, index) => item === lastDeps[index]);
        if (same) {
          // 如果相等,则直接更新状态索引
          setHookIndexAdd();
        } else {
          // 如果不相等,则执行上一次的清除函数,设置新的状态,并在延迟后执行回调函数
          oldDestroy();
          setHookStates(setHookIndexAdd(), [callback, deps]);
          setTimeout(callback);
        }
      } else {
        // 如果是第一次调用,则执行回调函数获取清除函数,并设置状态
        let destroy = callback();
        setHookStates(setHookIndexAdd(), [destroy, deps]);
      }
    };

示例用法

   const ExampleComponent = () => {
      useEffect(() => {
        console.log('Component mounted');
        return () => {
          console.log('Component unmounted');
        };
      }, []);
    ​
      return <div>Example Component</div>;
    };

useRef

useRef用于在函数组件中创建可变的引用的Hook。它返回一个包含可变引用的对象,该引用在组件的整个生命周期内保持不变。

源码逻辑

   // 导入 useState 和 useEffect
    import { useState, useEffect } from 'react';
    ​
    // useRef 实现
    export function useRef(initialValue) {
      // 使用 useState 创建一个状态 ref
      const [ref] = useState(() => ({
        current: initialValue,
      }));
    ​
      // 使用 useEffect 在 initialValue 变化时更新 ref 的 current 值
      useEffect(() => {
        ref.current = initialValue;
      }, [initialValue]);
    ​
      // 返回 ref 对象
      return ref;
    }

示例用法

 const ExampleComponent = () => {
      const inputRef = useRef(null);
    ​
      const focusInput = () => {
        inputRef.current.focus();
      };
    ​
      return (
        <div>
          <input ref={inputRef} />
          <button onClick={focusInput}>Focus Input</button>
        </div>
      );
    };

useContext

useContext用于在函数组件中访问上下文的Hook。它接受一个上下文对象,并返回该上下文的当前值。

源码逻辑

  export function useContext(context) {
      return context._currentValue;
    }

示例用法

 const MyContext = React.createContext();
    ​
    const ExampleComponent = () => {
      const value = useContext(MyContext);
    ​
      return <div>{value}</div>;
    };

useReducer

useReducer是用于在函数组件中管理状态的Hook。它接受一个状态更新函数和一个初始状态,并返回当前状态和一个派发状态更新的函数。

源码逻辑

  // 导入状态和状态索引相关的变量和函数
    import { hookStates, hookIndex, setHookStates, setHookIndexAdd } from './state';
    ​
    // useReducer 实现
    export function useReducer(reducer, initialState, render) {
      // 如果状态不存在,则设置初始状态
      hookStates[hookIndex] = hookStates[hookIndex] || initialState;
      let currentIndex = hookIndex;
    ​
      // 定义 dispatch 函数
      function dispatch(action) {
        // 根据 reducer 或者 action 更新状态
        hookStates[currentIndex] = reducer
          ? reducer(hookStates[currentIndex], action)
          : action;
        // 触发组件重新渲染
        render();
      }
    ​
      // 返回当前状态和 dispatch 函数
      return [hookStates[setHookIndexAdd()], dispatch];
    }
    ​

示例用法

  const initialState = { count: 0 };
    ​
    function reducer(state, action) {
      switch (action.type) {
        case 'increment':
          return { count: state.count + 1 };
        case 'decrement':
          return { count: state.count - 1 };
        default:
          return state;
      }
    }
    ​
    const ExampleComponent = () => {
      const [state, dispatch] = useReducer(reducer, initialState);
    ​
      const increment = () => {
        dispatch({ type: 'increment' });
      };
    ​
      const decrement = () => {
        dispatch({ type: 'decrement' });
      };
    ​
      return (
        <div>
          <p>Count: {state.count}</p>
          <button onClick={increment}>Increment</button>
          <button onClick={decrement}>Decrement</button>
        </div>
      );
    };