- packages目录(了解)
- 调试源码
- 深入理解JSX!
- React.createElement:jsx会被编译为React.createElement">React.createElement:jsx会被编译为React.createElement
- jsx与Fiber节点
源码的文件结构https://react.iamkasong.com/preparation/file.html
packages目录(了解)
react(opens new window)文件夹
React的核心,包含所有全局 React API,如:
- React.createElement
- React.Component
-
#scheduler(opens new window)文件夹
#shared(opens new window)文件夹
源码中其他模块公用的方法和全局变量,比如在shared/ReactSymbols.js(opens new window)中保存React不同组件类型的定义。
Renderer相关的文件夹
调试源码
https://react.iamkasong.com/preparation/source.html#%E6%8B%89%E5%8F%96%E6%BA%90%E7%A0%81
深入理解JSX!
// 编译前
<p>KaSong</p>
// 编译后
h("p", null, "KaSong");
React.createElement:jsx会被编译为React.createElement
在React中,所有JSX在运行时的返回结果,即(React.createElement()的返回值)都是ReactElement。 ```javascript 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;
if (config != null) { … //遍历config,将除保留属性外的其他属性赋值给props self = config.self === undefined ? null : config.self; source = config.source === undefined ? null : config.source; // Remaining properties are added to a new props object for (propName in config) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
props[propName] = config[propName];
}
} }
// Children can be more than one argument, and those are transferred onto // the newly allocated props object. //处理 children,会被赋值给props.children const childrenLength = arguments.length - 2; if (childrenLength === 1) { props.children = children; } else if (childrenLength > 1) { const childArray = Array(childrenLength); for (let i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
} … props.children = childArray; }
//处理 defaultProps 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, self, source, ReactCurrentOwner.current, props, ); }
const ReactElement = function(type, key, ref, self, source, owner, props) { const element = { // 标记这是个 React Element $$typeof: REACT_ELEMENT_TYPE,
// Built-in properties that belong on the element
type: type,
key: key,
ref: ref,
props: props,
// Record the component responsible for creating this element.
_owner: owner,
}; …
//最终返回element return element; };
//是否时合法的element 是object、不为null,且 object.$$typeof === REACT_ELEMENT_TYPE export function isValidElement(object) { return ( typeof object === ‘object’ && object !== null && object.$$typeof === REACT_ELEMENT_TYPE ); }
<a name="RUjpx"></a>
## React Component
```javascript
class AppClass extends React.Component {
render() {
return <p>KaSong</p>
}
}
console.log('这是ClassComponent:', AppClass);
console.log('这是Element:', <AppClass/>);
function AppFunc() {
return <p>KaSong</p>;
}
console.log('这是FunctionComponent:', AppFunc);
console.log('这是Element:', <AppFunc/>);
结果显示:ClassComponent对应的Element的type字段为AppClass自身。FunctionComponent对应的Element的type字段为AppFunc自身。
注意:
AppClass instanceof Function === true;
AppFunc instanceof Function === true;
所以无法通过引用类型区分ClassComponent和FunctionComponent。React通过ClassComponent实例原型上的isReactComponent变量判断是否是ClassComponent。
jsx与Fiber节点
JSX是一种描述当前组件内容的数据结构,它不包含schedule、reconcile、render所需的相关信息。
以下信息不包含在JSX中:
- 组件的更新中的优先级
- 组件的state
- 组件被打上的用于Renderer的标记
组件mount时,Reconciler根据jsx描述的组件内容生成组件对应的Fiber节点。
组件update时,Reconciler将JSX与Fiber节点保存的数据对比,生成组件对应的Fiber节点,并根据对比结果为Fiber节点打上标记。