Autor: JD Retail Zheng Bingyi
prefacio
React Hooks
es React
una nueva característica introducida en 16.8 que permite state
usar otras características de React en componentes de función sin tener que usar componentes de clase. Hooks
son un concepto muy importante porque proporcionan una React
experiencia de desarrollo más sencilla y comprensible.
React Hooks
El código fuente principal incluye principalmente dos partes: React
el administrador interno y una serie de funciones Hook
preestablecidasHook
.
Primero, veamos al gerente React
por dentro . Hook
Este administrador es React
un mecanismo interno importante responsable de administrar todo en el componente Hook
y asegurarse de que se llamen en el orden correcto durante la representación del componente.
Administrador de enlace interno
Ejemplo:
const Hook = {
queue: [],
current: null,
};
function useState(initialState) {
const state = Hook.current[Hook.queue.length];
if (!state) {
Hook.queue.push({
state: typeof initialState === 'function' ? initialState() : initialState,
setState(value) {
this.state = value;
render();
},
});
}
return [state.state, state.setState.bind(state)];
}
function useHook(callback) {
Hook.current = {
__proto__: Hook.current,
};
try {
callback();
} finally {
Hook.current = Hook.current.__proto__;
}
}
function render() {
useHook(() => {
const [count, setCount] = useState(0);
console.log('count:', count);
setTimeout(() => {
setCount(count + 1);
}, 1000);
});
}
render();
En este ejemplo, Hook
el objeto tiene dos propiedades importantes: queue
y current
. queue
Almacene todas Hook
las funciones de estado y actualización en el componente, y current
almacene una lista vinculada de los componentes que se están procesando actualmente Hook
. useState
y useHook
las funciones son responsables de crear un nuevo Hook
estado y usarlo en el componente , respectivamente Hook
.
Función de gancho preestablecido
Gancho useState
Aquí hay useState Hook
un ejemplo de implementación de:
function useState(initialState) {
const hook = updateWorkInProgressHook();
if (!hook.memoizedState) {
hook.memoizedState = [
typeof initialState === 'function' ? initialState() : initialState,
action => {
hook.queue.pending = true;
hook.queue.dispatch = action;
scheduleWork();
},
];
}
return hook.memoizedState;
}
El código anterior está implementado useState Hook
y su función principal es devolver una state
matriz con la función de actualización, y el valor inicial del estado es initialState
.
En esta implementación, updateWorkInProgressHook()
la función se utiliza para obtener el objeto de fibra del componente de función que se está ejecutando actualmente y determinar si existe uno correspondiente hook
. Se implementa de la siguiente manera:
function updateWorkInProgressHook() {
const fiber = getWorkInProgressFiber();
let hook = fiber.memoizedState;
if (hook) {
fiber.memoizedState = hook.next;
hook.next = null;
} else {
hook = {
memoizedState: null,
queue: {
pending: null,
dispatch: null,
last: null,
},
next: null,
};
}
workInProgressHook = hook;
return hook;
}
getWorkInProgressFiber()
La función se usa para obtener el objeto del componente de función que se está ejecutando actualmente fiber
y workInProgressHook
se usa para almacenar el hook
objeto que se está ejecutando actualmente. En un componente de función, cada useState
llamada crea un nuevo objeto de enlace y lo agrega a la lista vinculada fiber
de objetos hooks
. Esta hooks
lista enlazada se mantiene a través de las propiedades fiber
del objeto .memoizedState
También debemos tener en cuenta que en useState Hook
la implementación de , cada hook
objeto contiene un queue
objeto para almacenar el estado que se actualizará y la función de actualización. scheduleWork()
Las funciones se utilizan para notificar React
al programador que se debe ejecutar una tarea.
En React
el código fuente de , useState
la función es en realidad una useStateImpl
función interna llamada .
Aquí está useStateImpl
el código fuente:
function useStateImpl<S>(initialState: (() => S) | S): [S, Dispatch<SetStateAction<S>>] {
const dispatcher = resolveDispatcher();
return dispatcher.useState(initialState);
}
Se puede ver que useStateImpl
la función de la función es obtener la corriente dispatcher
y llamar a su useState
método, y devolver una matriz, el primer elemento es el valor del estado y el segundo elemento es una dispatch
función para actualizar el estado. La función aquí resolveDispatcher
se usa para obtener la actual dispatcher
, y su implementación es la siguiente:
function resolveDispatcher(): Dispatcher {
const dispatcher = currentlyRenderingFiber?.dispatcher;
if (dispatcher === undefined) {
throw new Error('Hooks can only be called inside the body of a function component. (https://fb.me/react-invalid-hook-call)');
}
return dispatcher;
}
resolveDispatcher
fiber
La función primero intenta obtener las propiedades del objeto que se está representando actualmente dispatcher
, y si no puede obtenerlo, dice
Si el componente no se encuentra actualmente en el proceso de renderizado, se generará un error.
Finalmente, echemos un vistazo a cómo se implementa el método useState
en una implementación específica . dispatcher
tomamos useReducer
_
dispatcher
Por ejemplo, se implementa de la siguiente manera:
export function useReducer<S, A>(
reducer: (prevState: S, action: A) => S,
initialState: S,
initialAction?: A,
): [S, Dispatch<A>] {
const [dispatch, currentState] = updateReducer<S, A>(
reducer,
// $FlowFixMe: Flow doesn't like mixed types
[initialState, initialAction],
// $FlowFixMe: Flow doesn't like mixed types
reducer === basicStateReducer ? basicStateReducer : updateStateReducer,
);
return [currentState, dispatch];
}
Como puede ver, useReducer
el método en realidad llama a una updateReducer
función llamada , que devuelve una dispatch
matriz que contiene el estado y la función actuales. updateReducer
La implementación de es más complicada e involucra muchos detalles, por lo que no la presentaré aquí.
useEffect Hook
useEffect
Es una función React
comúnmente utilizada en componentes para realizar operaciones de efectos secundarios en componentes, como acceder a datos remotos, agregar/eliminar detectores de eventos, operaciones manuales , etc. La función principal de es ejecutar la función de devolución de llamada de forma asíncrona después de que finaliza el proceso de representación del componente, y su implementación implica el mecanismo de representación asíncrona en React.Hook
DOM
useEffect
El siguiente es un ejemplo de implementación de useEffect Hook:
function useEffect(callback, dependencies) {
// 通过调用 useLayoutEffect 或者 useEffect 方法来获取当前的渲染批次
const batch = useContext(BatchContext);
// 根据当前的渲染批次判断是否需要执行回调函数
if (shouldFireEffect(batch, dependencies)) {
callback();
}
// 在组件被卸载时清除当前 effect 的状态信息
return () => clearEffect(batch);
}
En este ejemplo, useEffect
se reciben dos parámetros: una función de devolución de llamada y una matriz de dependencias. Cuando cambia cualquier valor en la matriz de dependencias,
React
useEffect
La función de devolución de llamada pasada se volverá a ejecutar en la próxima representación .
useEffect
La implementación de la función depende principalmente del React
mecanismo de representación asincrónica en . Cuando es necesario volver a renderizar un componente, React
todas state
las operaciones de actualización se agregarán a una cola y estas operaciones de actualización se ejecutarán de forma asíncrona después del final del lote de renderizado actual, evitando así múltiples operaciones de actualización consecutivas en el mismo lote de renderizado.
En useEffect
la función, obtenemos useContext(BatchContext)
el lote de representación actual llamando al método y shouldFireEffect
juzgamos si la función de devolución de llamada debe ejecutarse de acuerdo con el método. Después de ejecutar la función de devolución de llamada, debemos usar clearEffect
métodos para borrar la effect
información del estado actual para evitar que afecte los lotes de renderizado posteriores.
Resumir
En general, React Hooks
el principio de implementación del sistema no es complicado, depende principalmente de React
la fiber
estructura de datos internos y el sistema de programación, a través de estos mecanismos para realizar la gestión y actualización del estado del componente. Hooks
Nos permite usar el estado y otras características en componentes de función React
, haciendo que los componentes de función sean comparables a los componentes de clase.
Además de useState
, useEffect
etc . hook
, React
existen useContext
otros de uso común Hook
. Sus principios de implementación son básicamente similares y todos usan fiber
la arquitectura para implementar funciones como la administración de estado y los enlaces de ciclo de vida.
Los anteriores son hook
ejemplos de implementación simples, no son React
los códigos reales utilizados en , pero pueden ayudarnos a comprender mejor hook
la implementación central.