React Inside
- React
- 定义各种元素类型
- 定义上下文、状态规则
- ReactDOM
- 按约定渲染各种元素类型
- 事件 - 状态
- jsx - ReactElement
Fragmentjsx(Runtime) ->jsxWithValidationDynamic- 校验 type
- 校验 children
- 校验 children key
- 校验属性
- Fragment 只允许 children 和 key, 不允许存在 ref
- propTypes 校验
jsxs(Static) ->jsxWithValidationStatic- children 为数组
- Prod 环境
jsx=jsxs,且没有校验 - 保留属性
refkey- 会转为 string__self- 辅助判断this != owner__source- 转译时添加的辅助信息
- 新的 jsx 避免 spread key
- Feature
- ScopeAPI
- DebugTracing
- TransitionTracing
- SymbolFallbackForWWW
- LazyContextPropagation
- SuspenseAvoidThisFallback
- SuspenseAvoidThisFallbackFizz
- LegacyHidden
- UseRefAccessWarning
- StrictMode
createRootStrictEffectsByDefault
- 实验
- Cache
- CacheElement
- CPUSuspense
- API - React
ComponentPureComponent- 没有setState和forceUpdate方法memo- 创建
createElement(type,props,children)createFactory(type)
- 转换
cloneElement(element, config, children)- 会应用
defaultProps到 props - 会复制 children
- 会应用
isValidElement()$$typeof === REACT_ELEMENT_TYPE
Children
FragmentcreateRefforwardReflazy,SuspensestartTransition,useTransition- Hooks - 由
ReactCurrentDispatcher.currentDispatcher 处理 - 在 FC 渲染时设置- Basic -
useState,useEffect,useContext - Additional -
useReducer,useCallback,useMemo,useRef,useImperativeHandle,useDebugValueuseLayoutEffect=useEffect- DOM 操作后执行 -
componentDidMount,componentDidUpdate
- DOM 操作后执行 -
useDeferredValue- 低优先级- 类似于 debounce
const [isPending,startTransition]=useTransition()- Transition - 相对不那么着急更新的状态,耗时比较久的状态
- 用户基于已经更新的状态进行交互
useId- 生成唯一 ID
- Library
useSyncExternalStoreconst state = useSyncExternalStore(subscribe, getSnapshot[, getServerSnapshot])- 同步外部存储 - 例如 zustand
useInsertionEffect=useEffect- DOM 操作之前执行 - 用于 css-in-js 库
- Basic -
- 模块
react-is- 类型判断react-reconciler- 用于实现自定义渲染react-native-rendererreact-domreact-artreact-noop-renderer- used for debug fiber- Fiber - 之前为 同步 Stack Reconciler
- Building a simple custom renderer to DOM
- Building a simple custom renderer to native
react-refresh- bundlers 集成 fast refreshscheduler- 堆、优先级队列shareduse-subscriptionuse-sync-external-store- Experimental
react-server-react-server-{dom-relay,dom-webpack,native-relay}react-pgreact-cachereact-client- consuming React streaming modelsreact-fetchreact-fs- for react-server - experimental - bindings for the filesystem
// React 相关 Symbol - react.<nname>
// portal,fragment,provider,context,forward_ref,suspense,suspense_list
// memo,lazy,scope
// offscreen
// legacy_hidden
// cache
// tracing_marker
// default_value
// strick_mode,profiler,debug_trace_mode
// server_context
const REACT_ELEMENT_TYPE = Symbol.for('react.element');
const ReactElement = (type, key, ref, self, source, owner, props) => {
return {
// 类型识别
$$typeof: REACT_ELEMENT_TYPE,
// Built-in properties that belong on the element
type: type,
key: key,
ref: ref,
props: props, // dev 时 Object.freeze
// 创建该元素的组件
_owner: owner,
// dev 相关属性
_store: { validated: false },
_self: self,
_source: source,
};
};
function jsx(type, config, maybeKey, source, self) {
const { key, ref, __self, __source, ...props } = config;
return ReactElement(
type,
maybeKey || key || undefined,
ref,
// dev only
source,
self,
//
ReactCurrentOwner.current,
props,
);
}
const lazy = (ctor) => {
return {
$$typeof: REACT_LAZY_TYPE,
// Uninitialized -> Pending -> Resolved, Rejected
_payload: { _status: Uninitialized, _result: ctor },
// 会维护 _payload
// 非 Resolved 会 throw payload._result
_init: lazyInitializer,
};
};
const forwardRef = (render) => {
return { $$typeof: REACT_FORWARD_REF_TYPE, render };
};
const memo = (type: React$ElementType, compare?) => {
return {
$$typeof: REACT_MEMO_TYPE,
type,
compare: compare === undefined ? null : compare,
};
};
const createContext = (defaultValue) => {
const context = {
$$typeof: REACT_CONTEXT_TYPE,
_currentValue: defaultValue,
_currentValue2: defaultValue,
_threadCount: 0,
// These are circular
Provider: null,
Consumer: null,
// Add these to use same hidden class in VM as ServerContext
_defaultValue: null,
_globalName: null,
};
context.Provider = {
$$typeof: REACT_PROVIDER_TYPE,
_context: context,
};
context.Consumer = context;
return context;
};
class Component {
refs = {};
constructor(props, context, updater);
isReactComponent = {};
setState(partialState, callback) {
this.updater.enqueueSetState(this, partialState, callback, 'setState');
}
forceUpdate(callback) {
this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
}
}
Fiber
- 工作单位
- 两个阶段
- render - 异步、优先级、可中断、
beginWork - commit - 同步、
commitWork- WIP tree -> current tree
- render - 异步、优先级、可中断、
- 支持 HMR 能力 -
Function,Class,ForwardRef - 复用
ReactElement的 type 和 key createFiberFromXyzcreateFiberFromTypeAndProps- Fragment, Profiler, Suspense, SuspenseList, Offscreen, LegacyHidden
- Scope, Cache
- TracingMarker
- MemoComponent, LazyComponent
- ContextProvider, ContextConsumer
- HostComponent
- ClassComponent
beginWorkHooksDispatcherOnMount- 第一次 无状态时HooksDispatcherOnUpdate- 存在之前状态时- Lanes - 不同优先级队列
- SyncLane
- InputContinuousHydrationLane
- InputContinuousLane
- DefaultHydrationLane
- DefaultLane
- TransitionHydrationLane
- TransitionLanes
- RetryLanes
- SelectiveHydrationLane
- IdleHydrationLane
- IdleLane
- OffscreenLane
- Dispatcher -
memoizedStateuseCallback-[callback, deps]useDeferredValue-OnlyNonUrgentLanesuseContext
interface Fiber {
tag: WorkTag; // 工作类型
key;
type;
ref;
elementType; // element.type
stateNode;
pendingProps; // new,unresolved
memoizedProps; // old
updateQueue;
memoizedState; // hook
dependencies; // contexts, events
mode: TypeOfMode; // 运行类型
// Effect
flags: Flags;
subtreeFlags: Flags;
deletions: Array<Fiber> | null;
nextEffect: Fiber | null;
firstEffect: Fiber | null;
lastEffect: Fiber | null;
lanes: Lanes;
childLanes: Lanes;
// fiber 成对出现,这是另外一个 - 两个 tree 的 fiber
alternate: Fiber | null;
// 树 - 链表
return?: Fiber; // 上级节点
child?: Fiber; // 第一个子节点 - 多个子节点表现为 第一个的相邻节点
sibling?: Fiber; // 相邻节点
index: number;
// enableProfilerTimer
actualDuration?: number;
actualStartTime?: number;
selfBaseDuration?: number;
treeBaseDuration?: number;
}
interface Hook {
memoizedState: any;
baseState: any;
baseQueue: Update<any, any> | null;
queue: any;
// 更新时的 新的 Hook
next: Hook | null;
}
interface Effect {
// HasEffect,Insertion,Layout,Passive
tag: HookFlags;
create: () => (() => void) | void;
destroy: (() => void) | void;
deps: Array<mixed> | null;
next: Effect;
}
const createFiber = (tag: WorkTag, pendingProps: mixed, key: null | string, mode: TypeOfMode): Fiber => {
return new FiberNode(tag, pendingProps, key, mode);
};
const createWorkInProgress = (current: Fiber, pendingProps: any): Fiber => {
const wip = current.alternate ?? createFiber(current.tag, pendingProps, current.key, current.mode);
if (!current.alternate) {
wip.elementType = current.elementType;
wip.type = current.type;
wip.stateNode = current.stateNode;
wip.alternate = current;
current.alternate = wip;
}
// copy props from current to wip
return wip;
};
WorkTag
export const FunctionComponent = 0;
export const ClassComponent = 1;
export const IndeterminateComponent = 2; // Before we know whether it is function or class
export const HostRoot = 3; // Root of a host tree. Could be nested inside another node.
export const HostPortal = 4; // A subtree. Could be an entry point to a different renderer.
export const HostComponent = 5;
export const HostText = 6;
export const Fragment = 7;
export const Mode = 8;
export const ContextConsumer = 9;
export const ContextProvider = 10;
export const ForwardRef = 11;
export const Profiler = 12;
export const SuspenseComponent = 13;
export const MemoComponent = 14;
export const SimpleMemoComponent = 15;
export const LazyComponent = 16;
export const IncompleteClassComponent = 17;
export const DehydratedFragment = 18;
export const SuspenseListComponent = 19;
export const ScopeComponent = 21;
export const OffscreenComponent = 22;
export const LegacyHiddenComponent = 23;
export const CacheComponent = 24;
export const TracingMarkerComponent = 25;
TypeOfMode
export const NoMode = /* */ 0b000000;
// TODO: Remove ConcurrentMode by reading from the root tag instead
export const ConcurrentMode = /* */ 0b000001;
export const ProfileMode = /* */ 0b000010;
export const DebugTracingMode = /* */ 0b000100;
export const StrictLegacyMode = /* */ 0b001000;
export const StrictEffectsMode = /* */ 0b010000;
export const ConcurrentUpdatesByDefaultMode = /* */ 0b100000;
Fast Refresh
/* @refresh reset */
HMR - Hot Module Replacement
// vite
// deps, cb
import.meta.hot.accept((newModule) => {
if (newModule) {
// newModule is undefined when SyntaxError happened
console.log('updated: count is now ', newModule.count);
}
});
// webpack
import.meta.webpackHot.accept(
dependencies, // Either a string or an array of strings
callback, // Function to fire when the dependencies are updated
errorHandler, // (err, {moduleId, dependencyId}) => {}
);
- Vite HMR API
import.meta.hot- accept
- dispose
- data
- decline
- invalidate
- on
- send
- Webpack HMR API
- cjs
module.hot - esm
import.meta.webpackHot
- cjs
react-is
- 通过构造的
$$typeof来判断是否为内部对象类型 .$$typeof- ELEMENT
.type- FRAGMENT
- PROFILER
- STRICT_MODE
- SUSPENSE
- SUSPENSE_LIST
- PORTAL
- SERVER_CONTEXT
- CONTEXT
- FORWARD_REF
- LAZY
- MEMO
- PROVIDER
- ELEMENT
isAsyncMode- ReactIS
- ReactSymbols
react.elementreact.fragment- shared/ReactSymbols.js
Offscreen
const Offscreen = React.unstable_Offscreen;
const Hello = () => {
return (
<Offscreen mode={hidden ? 'hidden' : 'visible'}>
<Component />
</Offscreen>
);
};
- 还在 experimental
React.unstable_Offscreen- Offscreen Component
Experimental
- react act
- Cache
getCacheSignalgetCacheForTypeuseCacheRefreshuseMemoCacheuse
experimental_useEventDebugTraceModeOffscreenSuspenseList- react/index.experimental.js
Server Component
- 不支持特性
React.ComponentReact.PureComponentReact.createContext- hooks
- 约定
"use client","use server"标记组件类型- 会使用
react-serverexports
- RFC: Server Module Conventions