初探React中函數(shù)組件和類(lèi)組件的差異

    自從React Hooks的出來(lái),社區(qū)討論Hooks的越來(lái)越多。愛(ài)掏網(wǎng) - it200.com這并不是說(shuō)React Hooks就優(yōu)于類(lèi)組件,但是使用Hooks來(lái)構(gòu)建組件時(shí)有一個(gè)巨大的可用性提升,特別是因?yàn)檫@些函數(shù)組件可以通過(guò)React Hooks中的鉤子函數(shù)來(lái)訪問(wèn)狀態(tài)和生命周期。愛(ài)掏網(wǎng) - it200.com

    今天我們就來(lái)一起聊聊如何將React的類(lèi)組件轉(zhuǎn)換為函數(shù)組件,用React Hooks中的鉤子函數(shù)替換類(lèi)組件中的setState和生命周期方法,比如componentWillMountcomponentWillReceiveProps等。愛(ài)掏網(wǎng) - it200.com

    因此,讓我們首先使用狀態(tài)和生命周期方法構(gòu)建一個(gè)基于類(lèi)的React組件。愛(ài)掏網(wǎng) - it200.com也是大家最為熟悉的ToDoList組件。愛(ài)掏網(wǎng) - it200.com該組件具備:

    • 有一個(gè)文本輸入框(,用戶可以在輸入框中輸入想要的內(nèi)容
    • 有一個(gè)“添加列表項(xiàng)”按鈕(button,點(diǎn)擊該按鈕之后可以將文本輸入框的內(nèi)容添加到列表中(ToDoList中)
    • 顯示每個(gè)待辦事項(xiàng)的列表清單
    • 每個(gè)單獨(dú)的列表項(xiàng)目都有一個(gè)相關(guān)聯(lián)的復(fù)選框(),可以用來(lái)將列表項(xiàng)標(biāo)記為已完成
    • 列表項(xiàng)會(huì)存儲(chǔ)到瀏覽器的緩存中(本地存儲(chǔ)),并在應(yīng)用程序啟動(dòng)時(shí)從本地存儲(chǔ)中再次加載

    我們的組件將使用statecomponentDidMountcomponentDidUpdategetDerivedStateFromProps生命周期方法。愛(ài)掏網(wǎng) - it200.com其中一些生命周期方法(比如getDerivedStateFromProps)將以一種非人為方式使用,以便能夠演示有哪些Hooks的鉤子函數(shù)可以替換這些生命周期的方法。愛(ài)掏網(wǎng) - it200.com

    在開(kāi)始之前,先來(lái)學(xué)習(xí)關(guān)于類(lèi)和函數(shù)相關(guān)的知識(shí)點(diǎn)。愛(ài)掏網(wǎng) - it200.com

    作為Web開(kāi)發(fā)者,經(jīng)常和函數(shù)類(lèi)打交道。愛(ài)掏網(wǎng) - it200.com但要真正的理解和掌握他們也不是件易事,特別是對(duì)于初學(xué)JavaScript的同學(xué)更是如此。愛(ài)掏網(wǎng) - it200.com至少給我自己的感覺(jué)是如此。愛(ài)掏網(wǎng) - it200.com

    在這里我們不會(huì)深入的去聊函數(shù)和類(lèi),因?yàn)橐嬲牧耐杆麄儯伎梢匀?xiě)本書(shū)了。愛(ài)掏網(wǎng) - it200.com由于我們今天要聊React的類(lèi)組件和函數(shù)組件,那么在開(kāi)始之前很有必要的先了解一頂點(diǎn)有關(guān)于JavaScript的函數(shù)和類(lèi)。愛(ài)掏網(wǎng) - it200.com先來(lái)看函數(shù)吧。愛(ài)掏網(wǎng) - it200.com

    函數(shù)在JavaScript中被認(rèn)為是第一類(lèi)公民,在JavaScript中明確的創(chuàng)建函數(shù)的概念非常重要。愛(ài)掏網(wǎng) - it200.com

    JavaScript語(yǔ)言似乎和其他編程語(yǔ)言不同,我們可以在JavaScript中以不同的方式來(lái)創(chuàng)建一個(gè)函數(shù),常見(jiàn)的方式主要有:

    用幾個(gè)簡(jiǎn)單的示例代碼來(lái)演示他們之間的不同:

    // Function Declaration
    function Greeting(user) {
        console.log(`Hello, ${user}`)
    }
    
    Greeting('@w3cplus') // ? Hello, @w3cplus
    
    // Function Expression
    const Greeting = function(user) { // 作為對(duì)象分配給變量
        console.log(`Hello, ${user}`)
    }
    
    const Methods = {
        numbers: [1, 2, 8],
        // Function Expression
        sum: function() { // 在對(duì)象上創(chuàng)建一個(gè)方法
            return this.numbers.reduce(function(acc, num){ // Function Expression (使用該函數(shù)作為回調(diào)函數(shù))
                return acc + num
            })
        }
    }
    
    // Shorthand Method Definition
    const Collection = { // 用于Object Literals和ES6 Class聲明中
        items: [],
        // 使用函數(shù)名來(lái)定義
        // 使用一對(duì)圓括號(hào)中的參數(shù)列表和一對(duì)花括號(hào)來(lái)分隔主體語(yǔ)句
        add(...items) { 
            this.items.push(...items)
        },
        get(index) {
            return this.items[index]
        }
    }
    
    // Arrow Function
    let empty = () =>{}
    
    let simple = a => a > 15 ? 15 : a
    
    let max = (a, b) => a > b ? a : b
    
    let numbers = [1, 2, 3, 4]
    let sum = numbers.reduce((a, b) => a + b)
    let even = numbers.filter(v => v % 2 == 0)
    let double = numbers.map(v => v * 2)
    
    primise.then( a => {
        // ...
    }).then(b => {
        // ...
    })
    
    // Generator Function
    // JavaScript中的生成器函數(shù)返回這個(gè)生成器的迭代器對(duì)象
    
    function* indexGenerator() {
        var index = 0
        while(true) {
            yield index++
        }
    }
    
    const indexGenerator = function* () {
        var index = 0
        while(true) {
            yield index++
        }
    }
    
    const obj = {
        *indexGenerator() {
            var index = 0
            while(true) {
                yield index++
            }
        }
    }
    
    // Function Constructor
    const sum = new Function('a', 'b', 'return a + b')
    sum(1, 2) // ? 3
    

    類(lèi)是ES6中開(kāi)始引入的,實(shí)質(zhì)上是JavaScript現(xiàn)有的基于原型的繼承的語(yǔ)法糖。愛(ài)掏網(wǎng) - it200.com實(shí)際上,類(lèi)是特殊的函數(shù),就像你能夠定義的函數(shù)表達(dá)式和函數(shù)聲明一樣,類(lèi)語(yǔ)法主要有兩個(gè)組成部分:類(lèi)表達(dá)式類(lèi)聲明愛(ài)掏網(wǎng) - it200.com

    // 類(lèi)聲明
    class Rectangle {
        constructor(height, width) {
            this.height = height
            this.width = width
        }
    }
    
    // 類(lèi)表達(dá)式
    
    // 匿名類(lèi)
    let Rectangle = class {
        constructor(height, width) {
            this.height = height
            this.width = width
        }
    }
    
    // 命名類(lèi)
    let Rectangle = class Rectangle {
        constructor(height, width) {
            this.height = height
            this.width = width
        }
    }
    

    而且還可以使用extends關(guān)鍵字在類(lèi)聲明或類(lèi)表達(dá)式中用于創(chuàng)建一個(gè)類(lèi)作為另一個(gè)類(lèi)的子類(lèi):

    class Animal {
        constructor(name) {
            this.name = name
        }
    
        sayHi() {
            console.log(this.name)
        }
    }
    
    class Dog extends Animal {
        sayHi() {
            console.log(`${this.name} barks.`)
        }
    }
    let dog = new Dog('Mitzie')
    dog.sayHi() // ? Mitzie barks
    

    如果子類(lèi)中存在構(gòu)造函數(shù),則需要在使用this之前首先調(diào)用super()愛(ài)掏網(wǎng) - it200.com也可以擴(kuò)展傳統(tǒng)折基于函數(shù)的“類(lèi)”

    function Animal(name) {
        this.name = name
    }
    
    Animal.prototype.sayHi = function() {
        console.log(this.name)
    }
    
    class Dog extends Animal {
        sayHi() {
            super.sayHi()
            console.log(`${this.name} barks.`) 
        }
    }
    
    let dog = new Dog('Mitzie')
    dog.sayHi() 
    

    如果你想更深入的了解有關(guān)于JavaScript中的函數(shù)和類(lèi)相關(guān)的知識(shí)的話,可以花點(diǎn)時(shí)間閱讀下面相關(guān)文章:

    • 6 Ways to Declare JavaScript Functions
    • Understanding JavaScript Functions
    • How To Define Functions in JavaScript
    • Curry and Function Composition
    • Understanding JavaScript Callbacks and best practices
    • Understanding Classes in JavaScript
    • Understanding Prototypes and Inheritance in JavaScript
    • A Deep Dive into Classes
    • A Guide To Prototype-Based Class Inheritance In JavaScript
    • Understanding Public and Private Fields in JavaScript Class
    • 3 ways to define a JavaScript class
    • Object-oriented JavaScript: A Deep Dive into ES6 Classes
    • Demystifying Class in JavaScript
    • Javascript Classes — Under The Hood
    • JavaScript engine fundamentals: Shapes and Inline Caches
    • Understanding "Prototypes" in JavaScript
    • Advanced TypeScript Concepts: Classes and Types
    • A Beginner's Guide to JavaScript's Prototype

    我們回到React的世界當(dāng)中來(lái)。愛(ài)掏網(wǎng) - it200.com在React中我們可以以函數(shù)形式定義一個(gè)組件,比如像下面這樣:

    function SayHi() {
        return 

    Hello, React

    }

    也可以將SayHi這個(gè)組件以類(lèi)的形式來(lái)定義:

    class SayHi extends React.Component {
        render() {
            return 

    Hello, React

    } }

    在當(dāng)你要使用一個(gè)組件時(shí),比如要使用SayHi這個(gè)組件,并不會(huì)過(guò)多的關(guān)注它是以什么方式來(lái)定義(聲明)的組件,只會(huì)關(guān)心如何使用:

    雖然使用者不會(huì)太過(guò)關(guān)注它是怎么創(chuàng)建的(以哪種方式創(chuàng)建的),但React自身對(duì)于怎么創(chuàng)建組件是較為關(guān)注也會(huì)在意其差別。愛(ài)掏網(wǎng) - it200.com

    如果SayHi是一個(gè)函數(shù),React需要調(diào)用它:

    // 你的代碼
    function SayHi() {
        return 

    Hello, React

    } // React內(nèi)部 const result = SayHi(props) // ?

    Hello, React

    如果SayHi是一個(gè)類(lèi),React需要先用new操作符將其實(shí)例化,然后調(diào)用剛才生成實(shí)例的render方法:

    // 你的代碼
    class SayHi extends React.Component {
        render() {
            return 

    Hello, React

    } } // React內(nèi)部 const instance = new SayHi(props) // ? SayHi {} const result = instance.render() // ?

    Hello, React

    無(wú)論哪種情況,React的最終目標(biāo)是去獲取渲染后的DOM節(jié)點(diǎn),比如SayHi組件,獲取渲染后的DOM節(jié)點(diǎn)是:

    Hello, React

    具體需要取決于SayHi組件是怎么定義的。愛(ài)掏網(wǎng) - it200.com

    從上面的代碼中你可能已經(jīng)發(fā)現(xiàn)了,在調(diào)用類(lèi)時(shí),使用了new關(guān)鍵字來(lái)調(diào)用:

    // 如果SayHi是一個(gè)函數(shù)
    const result = SayHi(props); // ? 

    Hello, React

    // 如果SayHi是一個(gè)類(lèi) const instance = new SayHi(props) // ? SayHi {} const result = instance.render() // ?

    Hello, React

    那么JavaScript中的new起什么作用呢?在ES6之前,JavaScript是沒(méi)有類(lèi)(class)這樣的概念。愛(ài)掏網(wǎng) - it200.com在這種情況之前如果要使用類(lèi)這樣的特性都是使用普通函數(shù)來(lái)模擬。愛(ài)掏網(wǎng) - it200.com即,在函數(shù)調(diào)用前加上new關(guān)鍵字,就可以把任何函數(shù)當(dāng)做一個(gè)類(lèi)的構(gòu)造函數(shù)來(lái)用

    function Fruit(name) {
        this.name = name
    }
    
    const apple = new Fruit('apple') // ? Fruit?{name: "apple"}
    const banana = Fruit('banana')   // ? undefined   
    

    JavaScript中的new關(guān)鍵字會(huì)進(jìn)行如下的操作:

    • 創(chuàng)建一個(gè)空的對(duì)象,即{}
    • 鏈接該對(duì)象(即設(shè)置該對(duì)象的構(gòu)造函數(shù))到另一個(gè)對(duì)象
    • 將創(chuàng)建的對(duì)象作為this的上下文
    • 如果該函數(shù)沒(méi)有返回對(duì)象,則返回this

    正如上面的示例來(lái)說(shuō):

    • 調(diào)用Fruit('apple')時(shí)前面添加了new關(guān)鍵字,這個(gè)時(shí)候JavaScript會(huì)知道Fruit只是一個(gè)函數(shù),同時(shí)也會(huì)假裝它是一個(gè)構(gòu)造函數(shù)。愛(ài)掏網(wǎng) - it200.com會(huì)創(chuàng)建一個(gè)空對(duì)象({}并把Fruit中的this指向那個(gè)對(duì)象,以便我們可以通過(guò)類(lèi)似this.name的形式去設(shè)置一些東西,然后把這個(gè)對(duì)象返回
    • 調(diào)用Fruit('banana')時(shí)前面沒(méi)有添加new關(guān)鍵字,其中的this會(huì)指向某個(gè)全局且無(wú)用的東西,比如windowundefined,因此代碼會(huì)崩潰或者做一些像設(shè)置window.name之類(lèi)的傻事

    也就是說(shuō):

    // 和Fruit中的this是等效的對(duì)象
    const apple = new Fruit('apple') // ? Fruit?{name: "apple"}
    

    new關(guān)鍵字同時(shí)也把放在Fruit.prototype上的東西放到了apple對(duì)象上:

    function Fruit(name) {
        this.name = name
    }
    
    Fruit.prototype.SayHi = function () {
        console.log(`Hi,我想吃${this.name}`)
    }
    
    const apple = new Fruit('蘋(píng)果')
    
    apple.SayHi() // ? Hi,我想吃蘋(píng)果
    

    這就是在JavaScript中如何通過(guò)new關(guān)鍵字來(lái)模擬類(lèi)的方式。愛(ài)掏網(wǎng) - it200.com有關(guān)于new更多的介紹可以閱讀:

    • JavaScript’s new

    聲明:所有內(nèi)容來(lái)自互聯(lián)網(wǎng)搜索結(jié)果,不保證100%準(zhǔn)確性,僅供參考。如若本站內(nèi)容侵犯了原著者的合法權(quán)益,可聯(lián)系我們進(jìn)行處理。
    發(fā)表評(píng)論
    更多 網(wǎng)友評(píng)論0 條評(píng)論)
    暫無(wú)評(píng)論

    返回頂部

    主站蜘蛛池模板: 一区二区三区免费在线视频 | 亚洲国产精品自在线一区二区| 国产亚洲福利精品一区| 一区二区在线视频| www.亚洲一区| 一区二区精品视频| 国产精品一区二区四区| 亚洲一区二区三区四区视频| 狠狠色成人一区二区三区| 天码av无码一区二区三区四区 | 精品无码综合一区| 香蕉久久AⅤ一区二区三区| 四虎在线观看一区二区| 无码日韩人妻av一区免费| 无码国产精品一区二区免费式影视| 无码国产精品一区二区免费式芒果| 国产综合无码一区二区辣椒| 无码精品蜜桃一区二区三区WW| 精品福利一区二区三区免费视频 | 久久精品国产免费一区| 国产一区麻豆剧传媒果冻精品| 亚洲国产精品一区二区第一页免| 免费视频精品一区二区| 午夜无码一区二区三区在线观看| 一区二区三区免费视频观看| 国产综合视频在线观看一区| 一区二区三区高清在线| 久久国产精品一区| 自慰无码一区二区三区| 一区高清大胆人体| 国产激情一区二区三区小说| 国产精品区一区二区三| 日韩精品一区二区午夜成人版| 精品人体无码一区二区三区| 亚洲AV综合色区无码一区| 精品国产aⅴ无码一区二区| 国产一区二区不卡老阿姨| 日本在线视频一区| 午夜福利一区二区三区在线观看| 国产99久久精品一区二区| 精品视频一区二区|