저자: JD 소매 Zheng Bingyi
머리말
React Hooks
클래스 구성 요소를 사용하지 않고도 다른 React 기능을 함수 구성 요소에서 사용할 수 있도록 React
16.8에 도입된 새로운 기능 입니다 . 더 간단하고 이해하기 쉬운 개발 경험을 제공하기 때문에 매우 중요한 개념입니다 .state
Hooks
React
React Hooks
핵심 소스 코드는 주로 React
내부 Hook
관리자와 일련의 사전 설정 Hook
기능 의 두 부분으로 구성됩니다 .
React
먼저 내부의 Hook
관리자를 살펴보겠습니다 . 이 관리자는 React
구성 요소의 모든 것을 관리 Hook
하고 구성 요소 렌더링 중에 올바른 순서로 호출되는지 확인하는 중요한 내부 메커니즘입니다.
내부 후크 관리자
예:
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();
이 예에서 Hook
개체에는 두 가지 중요한 속성인 queue
및 가 있습니다 current
. queue
모든 Hook
상태 및 업데이트 기능을 구성 요소에 저장하고 current
현재 렌더링 중인 구성 요소의 연결된 목록을 저장합니다 Hook
. useState
및 useHook
함수는 각각 새 상태를 만들고 Hook
구성 요소에서 사용하는 역할을 합니다 Hook
.
프리셋 훅 기능
useState 후크
다음은 useState Hook
구현 예입니다.
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;
}
위의 코드는 구현되어 useState Hook
있으며 주요 기능은 업데이트 기능으로 배열을 반환하는 것이며 state
상태의 초기 값은 입니다 initialState
.
이 구현에서 updateWorkInProgressHook()
함수는 현재 실행 중인 함수 구성요소의 파이버 객체를 얻고 해당 항목이 있는지 확인하는 데 사용됩니다 hook
. 다음과 같이 구현됩니다.
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()
fiber
이 함수는 현재 실행 중인 함수 구성 요소의 개체를 가져오는 데 사용되며 workInProgressHook
현재 실행 중인 개체를 저장하는 데 사용됩니다 hook
. 함수 구성 요소에서 useState
호출할 때마다 새 후크 개체가 만들어지고 연결된 fiber
개체 목록에 추가됩니다 hooks
. 이 hooks
연결된 목록은 fiber
개체의 memoizedState
속성을 통해 유지 됩니다.
useState Hook
또한 의 구현에서 각 hook
개체에는 queue
업데이트할 상태와 업데이트 기능을 저장하는 개체가 포함되어 있다는 점에 유의해야 합니다 . 기능은 작업을 실행해야 함을 스케줄러에 scheduleWork()
알리는 데 사용됩니다 .React
React
의 소스 코드 에서 useState
함수는 실제로 useStateImpl
이라는 내부 함수입니다.
useStateImpl
다음은 소스 코드 입니다 .
function useStateImpl<S>(initialState: (() => S) | S): [S, Dispatch<SetStateAction<S>>] {
const dispatcher = resolveDispatcher();
return dispatcher.useState(initialState);
}
useStateImpl
함수의 기능은 현재를 얻어 dispatcher
그 메서드를 호출하고 useState
배열을 반환하는 것이고, 첫 번째 요소는 상태의 값이고, 두 번째 요소는 dispatch
상태를 업데이트하는 함수임을 알 수 있습니다 . 여기서 함수는 resolveDispatcher
현재 함수를 가져오는 데 사용되며 dispatcher
구현은 다음과 같습니다.
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
개체의 속성을 가져오려고 시도 dispatcher
하고 가져올 수 없으면 다음과 같이 말합니다.
구성 요소가 현재 렌더링 프로세스에 없으면 오류가 발생합니다.
useState
마지막으로 특정 구현에서 dispatcher
메서드가 어떻게 구현되는지 살펴보겠습니다 . 우리 useReducer
는
dispatcher
예를 들어 다음과 같이 구현됩니다.
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];
}
보시다시피 useReducer
이 메서드는 실제로 현재 상태와 함수를 포함하는 배열을 updateReducer
반환하는 이라는 함수를 호출합니다. 의 구현은 더 복잡하고 많은 세부 사항을 포함하므로 여기서는 소개하지 않겠습니다.dispatch
updateReducer
useEffect 후크
useEffect
원격 데이터 액세스, 이벤트 리스너 추가/제거, 수동 작업 등과 같은 구성 요소의 부작용 작업을 수행하기 위해 구성 요소 React
에서 일반적으로 사용되는 Hook
기능 입니다 . 의 핵심 기능은 컴포넌트의 렌더링 프로세스가 종료된 후 콜백 함수를 비동기적으로 실행하는 것이며, 그 구현에는 React의 비동기 렌더링 메커니즘이 포함됩니다.DOM
useEffect
다음은 useEffect Hook 구현의 예입니다.
function useEffect(callback, dependencies) {
// 通过调用 useLayoutEffect 或者 useEffect 方法来获取当前的渲染批次
const batch = useContext(BatchContext);
// 根据当前的渲染批次判断是否需要执行回调函数
if (shouldFireEffect(batch, dependencies)) {
callback();
}
// 在组件被卸载时清除当前 effect 的状态信息
return () => clearEffect(batch);
}
이 예에서는 useEffect
콜백 함수와 종속성 배열이라는 두 개의 매개변수가 수신됩니다. 종속성 배열의 값이 변경되면
React
useEffect
전달된 콜백 함수는 다음 렌더링에서 다시 실행됩니다 .
useEffect
함수의 구현은 주로 의 React
비동기 렌더링 메커니즘에 따라 달라집니다. 구성 요소를 다시 렌더링해야 하는 경우 React
모든 state
업데이트 작업이 대기열에 추가되고 이러한 업데이트 작업은 현재 렌더링 일괄 처리가 끝난 후 비동기적으로 실행되므로 동일한 렌더링 일괄 처리에서 여러 개의 연속적인 업데이트 작업을 방지할 수 있습니다.
useEffect
함수 에서 useContext(BatchContext)
메서드를 호출하여 현재 렌더링 배치를 가져오고 shouldFireEffect
메서드에 따라 콜백 함수를 실행해야 하는지 여부를 판단합니다. 콜백 함수가 실행된 후 후속 렌더링 배치에 영향을 주지 않도록 clearEffect
현재 상태 정보를 지우는 메서드를 사용해야 합니다 .effect
요약하다
일반적으로 React Hooks
시스템의 구현 원리는 복잡하지 않으며 주로 React
내부 fiber
데이터 구조 및 스케줄링 시스템에 의존하며 이러한 메커니즘을 통해 구성 요소 상태의 관리 및 업데이트를 실현합니다. Hooks
이를 통해 함수 구성 요소에서 상태 및 기타 기능을 사용할 수 있으므로 React
함수 구성 요소를 클래스 구성 요소와 비교할 수 있습니다.
useState
등 이외에도 일반적으로 사용 useEffect
되는 것들이 hook
있습니다 . 구현 원칙은 기본적으로 유사하며 모두 아키텍처를 사용하여 상태 관리 및 수명 주기 후크와 같은 기능을 구현합니다.React
useContext
Hook
fiber
위의 내용은 간단한 구현 예이며 에서 사용된 실제 코드는 hook
아니지만 핵심 구현을 더 잘 이해하는 데 도움이 될 수 있습니다.React
hook