ReactElement
key prop
// 尝试通过props获取key的时候,将会报错,不能把key作为prop来使用和看待
function defineKeyPropWarningGetter(props, displayName) {
const warnAboutAccessingKey = function() {
if (__DEV__) {
if (!specialPropKeyWarningShown) {
specialPropKeyWarningShown = true;
console.error(
'%s: `key` is not a prop. Trying to access it will result ' +
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://reactjs.org/link/special-props)',
displayName,
);
}
}
};
// key prop getter覆盖
warnAboutAccessingKey.isReactWarning = true;
Object.defineProperty(props, 'key', {
get: warnAboutAccessingKey,
configurable: true,
});
}
同理 ref也是
function defineRefPropWarningGetter(props, displayName) {
const warnAboutAccessingRef = function() {
if (__DEV__) {
if (!specialPropRefWarningShown) {
specialPropRefWarningShown = true;
console.error(
'%s: `ref` is not a prop. Trying to access it will result ' +
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://reactjs.org/link/special-props)',
displayName,
);
}
}
};
warnAboutAccessingRef.isReactWarning = true;
Object.defineProperty(props, 'ref', {
get: warnAboutAccessingRef,
configurable: true,
});
}
jsx方法
export function jsx(type, config, maybeKey) {
let propName;
// Reserved names are extracted
const props = {};
let key = null;
let ref = null;
// maybeKey 备选key
if (maybeKey !== undefined) {
key = '' + maybeKey;
}
// 校验key
if (hasValidKey(config)) {
key = '' + config.key;
}
// ref校验 不能为string
if (hasValidRef(config)) {
ref = config.ref;
}
// 开始处理props
for (propName in config) {
// config自身属性且不是保留字
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
props[propName] = config[propName];
}
}
// 保留字属性 自身属性 比如标签自己的属性 <a href="">
if (type && type.defaultProps) {
const defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
return ReactElement(
type,
key,
ref,
undefined,
undefined,
ReactCurrentOwner.current,
props,
);
}
createElement
export function createElement(type, config, children) {
let propName;
// Reserved names are extracted
const props = {};
let key = null;
let ref = null;
let self = null;
let source = null;
...
const childrenLength = arguments.length - 2;
// createElement(type, config, child)
if (childrenLength === 1) {
props.children = children;
} else if (childrenLength > 1) {
// createElement(type, config, child, child2, child3...)
const childArray = Array(childrenLength);
for (let i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
if (__DEV__) {
if (Object.freeze) {
Object.freeze(childArray);
}
}
props.children = childArray;
}
// Resolve default props
if (type && type.defaultProps) {
const defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
if (__DEV__) {
if (key || ref) {
const displayName =
typeof type === 'function'
? type.displayName || type.name || 'Unknown'
: type;
if (key) {
defineKeyPropWarningGetter(props, displayName);
}
if (ref) {
defineRefPropWarningGetter(props, displayName);
}
}
}
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
);
}
ReactContext
ReactLazy
懒加载组件兑现方法
function lazyInitializer<T>(payload: Payload<T>): T {
// 未初始化过的组件
if (payload._status === Uninitialized) {
const ctor = payload._result;
const thenable = ctor(); // 执行 获取promise
// Transition to the next state.
const pending: PendingPayload = (payload: any);
pending._status = Pending; // pending状态
pending._result = thenable;
thenable.then(
moduleObject => {
// 预防其他地方已经执行了获取方法了
if (payload._status === Pending) {
const defaultExport = moduleObject.default;
// Transition to the next state.
const resolved: ResolvedPayload<T> = (payload: any);
// 标记懒加载组件已resolved
resolved._status = Resolved;
// 拿到了组件导出结果
resolved._result = defaultExport;
}
},
error => {
if (payload._status === Pending) {
// Transition to the next state.
const rejected: RejectedPayload = (payload: any);
rejected._status = Rejected;
rejected._result = error;
}
},
);
}
if (payload._status === Resolved) {
return payload._result;
} else {
throw payload._result;
}
}
构造懒加载组件
export function lazy<T>(
ctor: () => Thenable<{default: T, ...}>,
): LazyComponent<T, Payload<T>> {
const payload: Payload<T> = {
_status: -1, // 未初始化状态
_result: ctor, // 获取方法 一般是构造promise的方法
};
const lazyType: LazyComponent<T, Payload<T>> = {
$$typeof: REACT_LAZY_TYPE,
_payload: payload,
_init: lazyInitializer,
};
return lazyType;
}
ReactForwardRef
forwardRef
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {REACT_FORWARD_REF_TYPE, REACT_MEMO_TYPE} from 'shared/ReactSymbols';
export function forwardRef<Props, ElementType: React$ElementType>(
render: (props: Props, ref: React$Ref<ElementType>) => React$Node,
) {
if (__DEV__) {
if (render != null && render.$$typeof === REACT_MEMO_TYPE) {
console.error(
'forwardRef requires a render function but received a `memo` ' +
'component. Instead of forwardRef(memo(...)), use ' +
'memo(forwardRef(...)).',
);
} else if (typeof render !== 'function') {
console.error(
'forwardRef requires a render function but was given %s.',
render === null ? 'null' : typeof render,
);
} else {
if (render.length !== 0 && render.length !== 2) {
console.error(
'forwardRef render functions accept exactly two parameters: props and ref. %s',
render.length === 1
? 'Did you forget to use the ref parameter?'
: 'Any additional parameter will be undefined.',
);
}
}
if (render != null) {
if (render.defaultProps != null || render.propTypes != null) {
console.error(
'forwardRef render functions do not support propTypes or defaultProps. ' +
'Did you accidentally pass a React component?',
);
}
}
}
const elementType = {
$$typeof: REACT_FORWARD_REF_TYPE,
render,
};
if (__DEV__) {
let ownName;
Object.defineProperty(elementType, 'displayName', {
enumerable: false,
configurable: true,
get: function() {
return ownName;
},
set: function(name) {
ownName = name;
if (render.displayName == null) {
render.displayName = name;
}
},
});
}
return elementType;
}
ReactMemo
memo
纯组件 只根据props,context等引发更新或者通过compare提供更新依据
export function memo<Props>(
type: React$ElementType,
compare?: (oldProps: Props, newProps: Props) => boolean,
) {
const elementType = {
$$typeof: REACT_MEMO_TYPE,
type,
compare: compare === undefined ? null : compare,
};
return elementType;
}
ReactHooks
function resolveDispatcher() {
// 也就是引用current做事情
const dispatcher = ReactCurrentDispatcher.current;
return ((dispatcher: any): Dispatcher);
}
export function useContext<T>(
Context: ReactContext<T>,
unstable_observedBits: number | boolean | void,
): T {
const dispatcher = resolveDispatcher();
if ((Context: any)._context !== undefined) {
const realContext = (Context: any)._context;
}
}
return dispatcher.useContext(Context, unstable_observedBits);
}
export function useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
const dispatcher = resolveDispatcher();
return dispatcher.useState(initialState);
}
export function useReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
const dispatcher = resolveDispatcher();
return dispatcher.useReducer(reducer, initialArg, init);
}
export function useRef<T>(initialValue: T): {|current: T|} {
const dispatcher = resolveDispatcher();
return dispatcher.useRef(initialValue);
}
export function useEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
const dispatcher = resolveDispatcher();
return dispatcher.useEffect(create, deps);
}
export function useLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
const dispatcher = resolveDispatcher();
return dispatcher.useLayoutEffect(create, deps);
}
export function useCallback<T>(
callback: T,
deps: Array<mixed> | void | null,
): T {
const dispatcher = resolveDispatcher();
return dispatcher.useCallback(callback, deps);
}
export function useMemo<T>(
create: () => T,
deps: Array<mixed> | void | null,
): T {
const dispatcher = resolveDispatcher();
return dispatcher.useMemo(create, deps);
}
export function useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
deps: Array<mixed> | void | null,
): void {
const dispatcher = resolveDispatcher();
return dispatcher.useImperativeHandle(ref, create, deps);
}
export function useDebugValue<T>(
value: T,
formatterFn: ?(value: T) => mixed,
): void {
if (__DEV__) {
const dispatcher = resolveDispatcher();
return dispatcher.useDebugValue(value, formatterFn);
}
}
export const emptyObject = {};
export function useTransition(): [(() => void) => void, boolean] {
const dispatcher = resolveDispatcher();
return dispatcher.useTransition();
}
export function useDeferredValue<T>(value: T): T {
const dispatcher = resolveDispatcher();
return dispatcher.useDeferredValue(value);
}
export function useOpaqueIdentifier(): OpaqueIDType | void {
const dispatcher = resolveDispatcher();
return dispatcher.useOpaqueIdentifier();
}
export function useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
const dispatcher = resolveDispatcher();
return dispatcher.useMutableSource(source, getSnapshot, subscribe);
}
export function useCacheRefresh(): <T>(?() => T, ?T) => void {
const dispatcher = resolveDispatcher();
// $FlowFixMe This is unstable, thus optional
return dispatcher.useCacheRefresh();
}