实际上,JSX 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖,因此,使用 JSX 可以完成的任何事情都可以通过纯 JavaScript 完成。
例如,用 JSX 编写的代码:
代码语言:javascript复制class Hello extends React.Component {
render() {
return <div>Hello {this.props.toWhat}</div>;
}
}
ReactDOM.render(
<Hello toWhat="World" />,
document.getElementById('root')
);
可以编写为不使用 JSX 的代码:
代码语言:javascript复制import { TEXT } from "../lreact/constant";
function createElement(type,config,...children){
// createElement 就是生成 {type:'xxx',children:[]}结构对象
if(config){
delete config.__self;
delete config.__source;
}
let props={
...config,
children:children.map(Child=>typeof Child==='object'?Child:createChild(Child))
}
return {
type,
props
}
}
function createChild(text){
return {
type:TEXT,
props:{
nodeValue:text,
children:[]
}
}
}
export class Component{
static isReactComponent={}
constructor(props){
this.props=props;
}
}
export default {
createElement,
Component
}
ReactDom.render实现
代码语言:javascript复制export const TEXT='text';
export const PLACEMENT="PLACEMENT";
export const UPDATE="UPDATE";
export const DELETION="DELETION"
// 正在处理的根fiber
let workInProgressRoot = null
// 下一个要处理的fiber
let nextUtilOfFiber = null
function render(vnode, container) {
// 此处要生成根fiber
workInProgressRoot = {
base:null,
node:container,
props: {
children: [vnode]
}
}
nextUtilOfFiber=workInProgressRoot;
}
function createNode(fiber){
const {type,props}=fiber;
let node=null;
if(type===TEXT){
node=document.createTextNode(props.nodeValue);
}else if(typeof type==='string'){
node=document.createElement(type);
}
updateProps(node,props);
return node;
}
// 更新所有的props除了children
function updateProps(node,props){
Object.keys(props).filter(i=>i!=='children').forEach(i=>node[i]=props[i])
}
function updateHostComponent(fiber){
if(!fiber.node){
fiber.node=createNode(fiber);
}
// 协调children
const { children } = fiber.props
reconcileChildren(fiber, children)
}
// 协调
function reconcileChildren(workInProgress,children){
let preFiber=null;
for(let i=0;i<children.length;i ){
let child=children[i];
let newFiber={
type:child.type,
props:child.props,
node:null,
base:null,
return:workInProgress,
effectTag: PLACEMENT
}
if(i===0){
workInProgress.child=newFiber
}else{
preFiber.sibling=newFiber
}
preFiber=newFiber;
}
}
function updateFunctionComponent(fiber){
const {type}=fiber;
let vnode=type(fiber.props);
reconcileChildren(fiber,[vnode]);
}
function updateClassComponent(fiber){
const {type}=fiber;
let vnode=new type(fiber.props);
reconcileChildren(fiber,[vnode.render()]);
}
// 处理这个fiber,并且返回一个fiber
function preNextUtilOfFiber(fiber) {
const {type}=fiber;
if(typeof type==='function'){
// 函数或者类组件
type.isReactComponent?updateClassComponent(fiber):updateFunctionComponent(fiber)
}else{
// 处理h5标记的fiber,并且协调儿子们
updateHostComponent(fiber);
}
// 有儿子先处理儿子
if(fiber.child){
return fiber.child;
}
console.log(fiber,99)
// 没儿子先处理弟弟,没弟弟找爸爸的弟弟
let nextFiber=fiber;
while(nextFiber){
if(nextFiber.sibling){
return nextFiber.sibling;
}
nextFiber=nextFiber.return;
}
return null;
}
function commitWorker(fiber){
if(!fiber){
return ;
}
// 找到最近的有真实dom的fiber
let parnetNodeFiber=fiber.return;
while(!parnetNodeFiber.node){
parnetNodeFiber=parnetNodeFiber.return;
}
// 将当前faber的node追加到付类
const parentNode=parnetNodeFiber.node;
if (fiber.effectTag === PLACEMENT && fiber.node !== null) {
// 如果有fiber.node加入到父节上
parentNode.appendChild(fiber.node);
}
// 一人得道,鸡犬声跳呢
commitWorker(fiber.child)
commitWorker(fiber.sibling)
}
function commitRoot() {
commitWorker(workInProgressRoot.child);
workInProgressRoot = null;
}
function workLoop(lealine) {
while (nextUtilOfFiber && lealine.timeRemaining() > 1) {
console.log(nextUtilOfFiber)
nextUtilOfFiber = preNextUtilOfFiber(nextUtilOfFiber);
}
if (!nextUtilOfFiber && workInProgressRoot) {
console.log(workInProgressRoot)
commitRoot()
}
requestIdleCallback(workLoop)
}
requestIdleCallback(workLoop)
export default {
render
}