1. 一篇必看的React文章

        共 4515字,需瀏覽 10分鐘

         ·

        2021-03-06 20:28

        本文適合有 React?基礎(chǔ)的小伙伴進(jìn)階學(xué)習(xí)


        作者:廣東靚仔

        一、前言

        本文基于開(kāi)源項(xiàng)目:

        https://github.com/facebook/react

        進(jìn)行簡(jiǎn)單的梳理,希望能夠讓讀者一文搞懂React 機(jī)制。

        1.React中文文檔

        ? ? 本文需要對(duì)React有所了解,如果暫時(shí)沒(méi)看過(guò)React,可以點(diǎn)擊下文,學(xué)習(xí)React基礎(chǔ)再來(lái)閱讀。

        傳送門(mén):?https://react.docschina.org/

        二、簡(jiǎn)單的demo

        ? ??

        ? ? 我們先來(lái)看個(gè)簡(jiǎn)單的demo


        0be3cb82f57f38ed53f916c9bda03f52.webp

        ? ? 上面是一個(gè)簡(jiǎn)單的例子,很容易猜到頁(yè)面會(huì)刪除“前端早茶”文字,以及一個(gè)按鈕“點(diǎn)我關(guān)注”。

        ? ? 接下來(lái),我們刪除?import React from 'react'?刪除這行代碼,然后仍要得到同樣的效果,怎么實(shí)現(xiàn)呢?

        ? ??毫無(wú)疑問(wèn),我們需要實(shí)現(xiàn)自己的React,項(xiàng)目目錄結(jié)構(gòu)如下:

        +--?src?????????????????//?開(kāi)發(fā)目錄
        |???+-- gdlz ???????????//?存放自己實(shí)現(xiàn)react(文件名:廣東靚仔)
        |???|????+--index.js????//?自己react的邏輯
        |???+--index.js?????????//?主頁(yè)面


        主頁(yè)面index.js代碼如下:

        /*
        ?*?@Author:?前端早茶
        ?*?@Date:?2021-03-05?21:59:06
        ?*?@LastEditTime:?2021-03-06?07:28:44
        ?*?@Description:?my?react
        ?*?@FilePath:?/reactDemo/src/index.js
        ?*/

        import?React?from?'./gdlz'
        const?ReactDOM?=?React
        class?Child?extends?React.Component{
        ??constructor?(props)?{
        ????super(props)
        ????this.state?=?{
        ??????count:?1
        ????}
        ??}
        ??handleClick?=?()?=>?{
        ????this.setState({
        ??????count:?this.state.count + 1
        ????})
        ??}
        ??render?()?{
        ????return?<div>
        ??????<h2?onClick={this.handleClick}>{this.state.count}</h2>
        ????</div>

        ??}
        }
        ChildComponent?=?React.useComponent(Child)

        function?App?(props){
        ??const?[count,?setCount]?=?React.useState(1)
        ??return?<div?id="container"?className="front-end">
        ????<h1>{props.title},?{count}</h1>
        ????<button?onClick={()?=>?setCount(count+1)}>關(guān)注</button>
        ????<hr/>
        ????<ChildComponent></ChildComponent>
        ??</div>

        }
        let?element?=?<App?title="前端早茶"?/>

        ReactDOM.render(element,?document.getElementById('root'))


        從上面的代碼中,我們可以看到,主頁(yè)面index里面有:

        ?React.Component

        ?React.useComponent

        ?React.useState

        ?ReactDOM.render


        因此我們需要實(shí)現(xiàn):

        Component,

        useComponent

        useState,

        render,

        需要注意,createElement 是我們的基礎(chǔ),具體原因是因?yàn)镽eact使用的是JSX,需要轉(zhuǎn)為React.createElement的。


        我截取了React官網(wǎng)的一個(gè)demo,大家會(huì)更直觀


        af8d58f4e2486a8a60a330c7d361f85d.webp


        自己的React里面最后要導(dǎo)出內(nèi)容如下:


        34a825f757efd423ff49eddf69328fc1.webp


        三、createElement


        /**
        ?*?@description:?createElement?函數(shù)
        ?*?@param?{*}?type?類型
        ?*?@param?{*}?props?參數(shù)
        ?*?@param?{array}?children?子元素
        ?*?@return?{*}?對(duì)象
        ?*/

        function?createElement(type,?props,?...children)?{
        ??return?{
        ????type,
        ????props:?{
        ??????...props,
        ??????children:?children.map(child?=>
        ????????typeof?child?===?"object"
        ????????????child
        ??????????:?createTextElement(child)
        ??????),
        ????},
        ??}

        /**
        ?*?@description:?createTextElement?函數(shù)
        ?*?@param?{*}?text?文本,用于直接渲染文字
        ?*?@return?{*}?對(duì)象
        ?*/

        function?createTextElement(text)?{
        ??return?{
        ????type:?"TEXT",
        ????props:?{
        ??????nodeValue:?text,
        ??????children:?[],
        ????},
        ??}
        }

        四、Component、useComponent

        /**
        ?*?@description:?Component?組件函數(shù)
        ?*?@param?{*}
        ?*?@return?{*}
        ?*/

        class?Component?{
        ??constructor(props){
        ????this.props?=?props
        ??}
        }
        /**
        ?*?@description:?useComponent
        ?*?@param?{*}?Component?傳入的class組件
        ?*?@return?{*}
        ?*/

        function?useComponent(Component){
        ??return?function(props){
        ????const?component?=?new?Component(props)
        ????let?[state,?setState]?=?useState(component.state)
        ????component.props?=?props
        ????component.state?=?state
        ????component.setState?=?setState
        ????console.log(component)
        ????return?component.render()
        ??}
        }


        五、useState


        //?下一個(gè)單元任務(wù)
        let?nextUnitOfWork?=?null
        //?工作中的fiber
        let?wipRoot?=?null
        let?currentRoot?=?null
        let?deletions?=?null
        let?wipFiber?=?null
        let?hookIndex?=?null
        /**
        ?*?@description:?useState?函數(shù)
        ?*?@param?{*}?init?component.state
        ?*?@return?{*}
        ?*/

        function?useState(init){
        ??const?oldHook?=
        ??wipFiber.base?&&
        ??wipFiber.base.hooks?&&
        ??wipFiber.base.hooks[hookIndex]
        ??const?hook?=?{
        ????state:?oldHook???oldHook.state?:?init,
        ????queue:?[],
        ??}
        ??const?actions?=?oldHook???oldHook.queue?:?[]
        ??actions.forEach(action?=>?{
        ????hook.state?=?action
        ??})
        ??const?setState?=?action?=>?{
        ????hook.queue.push(action)
        ????wipRoot?=?{
        ??????dom:?currentRoot.dom,
        ??????props:?currentRoot.props,
        ??????base:?currentRoot,
        ????}
        ????nextUnitOfWork?=?wipRoot
        ????deletions?=?[]
        ??}
        ??wipFiber.hooks.push(hook)
        ??hookIndex++
        ??return?[hook.state,?setState]
        }

        六、render


        //?設(shè)置全局?下一個(gè)任務(wù)單元
        let?nextUnitOfWork?=?null
        /**
        ?*?@description:?render函數(shù)
        ?*?@param?{*}?vdom?虛擬dom
        ?*?@param {*} container 容器
        ?*?@return?{*}
        ?*/

        function?render(vdom,?container){
        ??//?工作中的fiber?
        ??wipRoot?=?{
        ????dom:?container,
        ????props:?{
        ??????children:?[vdom],
        ????},
        ????base:?currentRoot,
        ??}
        ??deletions?=?[]
        ??nextUnitOfWork?=?wipRoot
        }

        ? ? 從這個(gè)render可以看到,我們里面有使用到下一個(gè)任務(wù)單元,很明顯會(huì)涉及到協(xié)調(diào)調(diào)度children的邏輯。由于篇幅關(guān)系這里簡(jiǎn)單描述一下:

        ? ? 任務(wù)調(diào)度reconcileChildren

        ? ? 假如當(dāng)前有任務(wù),而且當(dāng)前幀還沒(méi)結(jié)束,我們獲取下一個(gè)任務(wù)單元,并且記錄起來(lái)。當(dāng)沒(méi)有下一個(gè)任務(wù)了,咋們提交root。在這當(dāng)中我們會(huì)使用到window.requestIdleCallback()這個(gè)函數(shù)。其作用是在瀏覽器的空閑時(shí)段內(nèi)調(diào)用的函數(shù)排隊(duì),函數(shù)一般會(huì)按先進(jìn)先調(diào)用的順序執(zhí)行。關(guān)于這個(gè)函數(shù)的具體介紹,我們可以在MDN進(jìn)行閱讀。

        這里稍微提一下,React17如果子節(jié)點(diǎn)是數(shù)組,會(huì)調(diào)用reconcileChildrenArray。

        七、總結(jié)

        ? ? 我們實(shí)現(xiàn)了一個(gè)自己的React,很明顯我們有很多細(xì)節(jié)沒(méi)有考慮進(jìn)去。不過(guò)經(jīng)過(guò)梳理我們現(xiàn)在對(duì)React有了一個(gè)清晰的認(rèn)識(shí),閱讀源碼的時(shí)候我們分塊進(jìn)行理解,化整為零~

        關(guān)注前端早茶,我們一起學(xué)習(xí),共同進(jìn)步

        瀏覽 44
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 丰满人妻一区二区三区 | 天天干天天撸天天日 | 亚洲人成免费电影 | 精品人妻91 | 久久久久亚洲精品男人的天堂 |