不懂函数式?用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,能够省去各类配置。

相关文章
相关标签/搜索