不懂函數式?用mobx來寫react應用吧

目的

直接了當吧:其實這篇就是想安利你們一個新的狀態管理庫。若是你使用react,更熟悉面向對象,羨慕vue的簡單直觀,對redux感受有些煩躁,真心安利你,體驗下mobx.javascript

安利的同時,略帶些內容。內容走起html

內容

由於看到redux的做者,在twitter推薦了mobx這個庫:vue

unhappy with redux? try mobxjava

大神主動推薦本身成名做品的替代品?!!!react

因而立馬嘗試。不到一個下午的時間,基本上手,而後晚上回去想了想代碼組織的問題,試用了起來。發現開發效率大幅提高,並且整個工程的脈絡很清楚。jquery

而後回想起當初學redux,真感受本身智商不夠。看了一週文檔,理念理解的七七八八,不知道如何寫代碼;而後由於源碼很少,又看了一週redux的源碼,還發現了個bug,提了pr,可是依舊不知道如何寫代碼。。最後只能硬着頭皮無腦抄別人的代碼,才大體明白了整個流程。git

因此從自身實際狀況的對比,有段時間略傻x的變成了redux無腦黑,並在不少場合說過,誰用redux誰加班。。。如今想一想too simplees6

通過不斷的討論,以爲使用redux不爽,最大的緣由是不熟悉函數式,並且js自己也沒有在語法上爲函數式提供什麼便利。github

redux更像是定了一種規範,而後爲了能把這種規範應用到工程中,提供了幾個幫助函數。若是對函數式很熟悉,那麼會很是認同這套並很舒服的使用起來。ajax

可是,熟悉函數式的工程師數量遠比熟悉面向對象的少,我對函數式也就只瞭解個皮毛。。

言歸正傳,來看看mobx吧.

使用mobx的寫react,大致上,步驟分爲兩步:

  1. 寫模型的class

import $ from 'jquery' // just for ajax usage
    import { observable } from 'mobx'
    
    class Posts{
        @observable list=[]
        
        //這裏爲了演示,直接$.ajax。
        //可是這樣的model,很難測試!!
        fetchPosts(){
            $.ajax({
                url:'/posts'
            }).done((data)=>{
                this.list = data.postList
            })
        }
    }

這個對於熟悉OOP的人,親切的不行,寫model類這事,有點經驗的工程師,沒寫個上千個,也寫個幾百個吧。異步的處理,也很直白,請求,而後根據請求的數據,處理相應的屬性。這段代碼,若是不引入es6的語法,和之前jquery時代,寫model沒啥區別。

這裏多了個 @observabledecorator目前在es7裏還沒定稿,經過babel 6使用也須要經過引入一個plugin,這裏使用,能能夠提升可讀性。固然不使用decorator也能夠,原理上,就是給list包了個函數,這個函數會對list進行處理,讓對list的讀寫擁有了pub/sub的功能。

固然mobx提供的功能要比這多不少,根據官方描述

MobX is a battle tested library that makes state management simple and scalable by transparently applying functional reactive programming (TFRP)

你們注意兩點 battle testedtransparently applying functional reactive programming

mobx作了大量的工做,能讓你只關注操做對象屬性便可,而背後的理念,就一句話

Anything that can be derived from the application state, should be derived. Automatically.

應用的狀態是本源,其餘的部分,都應該從本源導出(derived)。好比上面的Posts類,本源就是 @observable list.而後其餘部分,依賴這個list去作一些事情,好比 mobx提供了autorun函數

//寫在 class Posts裏
autorun(()=>console.log(this.list.length))

autorun裏的匿名函數對list進行了取值,mobx知道,這個反作用函數,依賴list,因此list有變更,都會執行這個函數。這個函數的運行,是list這個應用狀態驅動的。若是應用還有其餘狀態,mobx不會觸發這個函數,由於這個函數只依賴 list.

使用react後,ui的變化也是狀態變化後,產生的反作用。因此很天然

autorun(()=> redner(this.list))

那麼狀態的變化,就引發ui的變化,並且僅當this.list變化,纔會引發ui的變化,其餘應用狀態的變化,不會產生影響,這也是mobx不需特別性能優化的緣由,只有相關狀態變更,纔會影響ui。實際上,在只render須要render的組件方面,官方出的mobx-react作了更多的工做。

2.寫react組件

有了上面的class Posts,咱們有個組件要展現post list

import React from 'react'
    import { observer } from 'mobx-react'
    import Posts from './Posts'
    
    @observer
    class PostListComp extends React.component {
        contructor() {
            this.posts = new Posts();
            this.posts.fetchPosts()
        }
        
        render() {
            return (
                <ul>
                    {this.posts.list.map((post)=>(
                        <li key={post.id}>post.title</li>
                    ))}
                </ul>
            )
        }
    }

這裏Posts實例不打算全局使用,因此賦值在 this.posts上。開始的時候,this.posts.list是[],這ok,ul裏是空的,fetchPosts中異步請求結束,this.posts.list就有了從服務器取來的數據,這時mobx知道,這個react組件依賴於this.post.list,那渲染吧,就這樣。

這裏的狀態是PostListComp組件本身new處理的,不和其餘組件共享;若是想共享,能夠放在兩個組件的共同祖先那實例化,而後再各自傳入,甚至根據業務,能夠作成全局的單例。想一想你處理對象的技巧,都能用在這裏,若是你想用DI來管理這些對象,也能夠,有文章介紹了mobx結合InversifyJS使用的狀況。

若是posts是父組件傳給PostListComp的,若是父組件的渲染不須要posts.list,posts.list的變化只會重渲染 PostListComp,而不會重渲染父組件。只render須要render的組件,因此性能優越。甚至能夠作到下面這樣(先不要糾結下面代碼的一些細節)

const profileView = observer(props => {
       if (props.person.nickName)
          return <div>{props.person.nickName}</div>
    else
          return <div>{props.person.fullName}</div>
   });

若是nickName不爲空,那麼mobx知道,這個view只依賴於nickName,fullName的變更不會引發view的變化,從而不會重新render組件。只render須要render的組件(這話我已經說了3遍了!)

其餘的api

mobx還提供了其餘一些api,相對高級點,好比

  1. @computed: 由最開始的state生成出來的state,好比 fullName是由firstName和lastName生成的,若是firstName改變,fullName會重計算。監聽@computed屬性,和監聽@observable屬性,在使用上是同樣的。理論上,能夠寫無數多層這樣的依賴。

  2. untrack:在某一時刻使用了state的某個屬性,可是不想對這個state屬性產生依賴

  3. transaction:在transaction塊中執行的屬性修改,只會在塊結束時,觸發一次Derivations的變動或執行。這就避免了沒必要要的屢次反作用,好比屢次 render react組件。

  4. useStrict: 非嚴格模式下的mobx,任何地方均可以修改state,這樣很快就會讓state的管理難以維護。嚴格模式下,只有標記了@action的函數或在runInAction中的代碼,才能修改state。這個強烈建議使用

  5. spy & intercept 作單個state或全局全部state的攔截。這給log等功能,提供了很好的便利。

還有一些,你們去讀文檔吧。

題外話

model改變,ui自動變化,mobx寫着,讓我頗有vue的感受。感受就是多了幾個decorator.

缺點

社區還不夠豐富。mobx的資料還很少,基本沒有中文資料。我安利的同窗,都反映官方的get start(英文)看着有點蛋疼。而後我說,想一想大家寫redux的第一個demo,而後他們表示剛纔的疼不算什麼~。

相信你們手上已經有些項目用redux了,若是用着也算順手,其實也就不必換了。我本人也同時維護着使用redux的項目,而後在新項目裏使用mobx,個人效率是大幅提高的,可是老項目重寫的代價太大。。。

結論

因此,若是你使用react,更熟悉面向對象,羨慕vue的簡單直觀,真心安利你,體驗下mobx。寫的很舒爽,並且程序的性能有保證。對了官方還提供了一個dev-tools,很是不錯,可以直接看到哪些組件被重渲染了。

若是你被安利成功,想看看mobx,建議從官方文檔開始,或者去官方的推薦列表裏,找找視頻教程(不要想,確定是英文的),地址是 http://mobxjs.github.io/mobx/faq/blogs.html

官方還提供了一個starter,能夠省去各類配置。

相關文章
相關標籤/搜索