走原始碼路線,淺談react的一些思路

世博發表於2019-02-27

你的簡單不簡單,你的困難真的難

公司專案進,時間週期不夠,個人感覺腳手架真的是個入門直接開發的快速選擇,

搭建環境

首先需要安裝node環境 略

    npm install -g creat-react-app//全域性安裝腳手架,任何地方都可以隨時建立專案
    create reactApp//建立一個reactApp目錄 並將有所依賴以及配置檔案放入
    cd reactApp//進入目錄
    npm start//啟動專案
複製程式碼

你已經成功啟動了一個react專案。

基本上就是這麼一個目錄結構

React主要核心庫

import React from `react`;
import ReactDom from `react-dom`;

ReactDom.render(
    <h1>hello</h1>,
    document.getElementById(`root`)
)

複製程式碼

最早的版本,react和react-dom這倆個是放在一起的,後來因為各種架構的優點,互補互惠。將react-dom給拆分出來,react相當於庫的核心,其他的衍生的react庫都如同女朋友一樣偎在他身邊。可以隨時更換隨時使用。

這些太low了,直接講原始碼,

    let objMale = <div>hello</divh1>;  等價於  React.createElement(`div`,null,[`hello`]);
    js都是可以巢狀的,react當然也可以
    let objFemale = <div>hello<span>juejin</span> 等價於 React.createElement(`div`,null,[React.createElement(`span`,null,[`juejin`])]);
    console.log(objMale);
複製程式碼

為什麼呢,這裡需要一個圖來解釋一下,

走原始碼路線,淺談react的一些思路

就是這麼簡單(科普一下為什麼外層render下面只能有一個單一根節點,並不是收到jsx的限制,而是因為每個被react渲染的元素都會是一個返回值)

    let obj = <div>hello</div>//這裡最終是會return React.createElement(`div`,null,[`hello`]);
    
    如果我在 元件類中  render(){
        return (
            <div>1</div>
            <div>2</div>
        )
    }
    並不是說這不合法,而是因為走到第一個div的時候就已經直接return 出結果,不會向下繼續執行。--知識點哦
複製程式碼

現在開始,我們們先來了解一下最簡單的render方法

剛才列印出來的objMale,你會發現在控制檯中展示的是一個物件,這是react特有的物件,然後type對應h1,props對應內部文字節點

let objMale = {
    type:`div`,
    props:{
        children:[`hello`]
    }
};
//大致是這樣的一個結構,這已經成為我們可以看懂的js物件了吧。

然後開始分析程式碼,ReactDom.render(objMale,document.getElementById(`root`)),這一層render做了什麼事情
客觀分析,定義了一個JSX Dom元素,<div>hello</div>,render只是將他給插入到頁面中

簡單定義一個函式 _render 名字隨便起

function _render(jsxDom,container){
    //首先通過解構賦值   然後建立一個元素節點吧。
    let {type,props} = jsxDom;
    let newEle = document.createElement(type);//注意手法,這裡就是將jsxDom,通過type為div 的轉換成一個Dom元素
        
        <!--
            下一步操作 _nextRender (主要目的就是將props中的內容給新增到新建立的Dom元素中)
        -->
    
    //最終輸出的就是講建立的DOM元素插入到容器 -->
    container.appendChild(newEle)
}
_render(objMale,document.getElementById(`root`));

//大體來說無非就是這種操作,下一步也就是把渲染的元素加上相應的文字節點,
//可以列印一下 React.createElement(`div`,{id:1,className:`girl`},[`hello`]) 這個物件看一下props
function _nextRender(newEle,props){
    //props不僅僅可能是一個物件
    for ( let attr in props){
        //介於react中的一些關鍵字不能和js中衝突,,jsx className  <=> class class   jsxom htmlFor <=> js for
        //這裡需要加一些判斷
        if(attr == `children`){
            //這裡對應上面擴充套件的巢狀邏輯  我的children裡面也可能是個物件吧。這時候就要用到遞迴(知識點哦)

            props.forEach((item)=>{
                //這裡只有倆種可能,一種是字串,一種是子元素(子元素依然會和父元素的jsxDom保持一致)
                if(typeof item == `string`){ //判斷為字串  直接新增
                    newEle.appendChild(item)
                }else{    //否則就是元素   遞迴,,_render(當前子元素物件,上一級建立的容器)
                    _render(item,newEle);
                }                
            })
        }else if (attr == `className`){
            newEle.setAttribute(`class`,props[attr])
        }else if(attr == `className`){
            newEle.setAttribute(`for`,props[attr])
        }else{
            newEle.setAttribute(attrr`,props[attr])
        }
        
    }
}

let mulObj = {
    type:`div`,
    props:{
        className:`ai`,
        id:1,
        children:[`hello`,{
            type:`span`,
            props:{
                className:`xi`,
                id:2,
                children:[`juejin`]
            }
        }]
    }
};
let jsxObj = <div className="ai" id="1">hello<span className="xi" id="2">juejin</span></div>
最終渲染在頁面上就都是  <div class="ai" id="1">hello<span class="xi" id="2">juejin</span></div>


_render(mulObj,document.getElementById(`root`)); === ReactDom.render(jsxObj,document.getElementById(`root`))
並不是完全相等,只是在渲染邏輯上差不多。
複製程式碼

難著不會,會者不難。

跟隨大神的腳步,我也一樣可以天天吃雞蛋喝牛奶
走原始碼路線,淺談react的一些思路

相關文章