美文网首页RN
初识 MobX + React-Native + React R

初识 MobX + React-Native + React R

作者: jevons_lee_ | 来源:发表于2019-03-18 15:42 被阅读27次

    MobX

    简单、可扩展的状态管理(可观察的数据)


    使用:

    安装: npm install mobx --save

    React 绑定库: npm install mobx-react --save

    引用 : import { observable } from 'mobx';


    Api

    observable



    什么是 observable ?

    observable 是一种让数据的变化可观察的方法

    哪些数据类型可以被观察 ?

    • 原始类型:string,number,boolean,symbol
    • 对象
    • 数组

    如何用 observable 把对象转化为可观察到对象

    MobX 对任意变量的处理方式有两种

    1.  对于数组纯对象以及 es6 中的 map ,直接把 observable 当作函数来把变量转化为可观察到对象,之后对数组、对象、map 中的内部数据进行合理的操作,都将会被监视

    const map = observable(new Map());
    map.set('a',1);
    console.log(map.has('a'));
    map.delete('a');
    console.log(map.has('a'));
    

    2.  对于上面没有包含的其他类型,都将调用 observable.box来进行把变量包装为可观察到对象,之后对该变量的直接负值将会被监视

    const str = observable.box(2);
    const num = observable.box(2);
    const bool = observable.box(2);
    num.set(3)
    console.log('---observable---', str, num.get(), bool.get())
    
    • .get() - 返回原始类型值。

    • .set(value) - 替换当前存储的值并通知 observable。

    对于 todolist 的 demo 来讲

    • 每一次对Todos更改都会触发change(例如:添加,删除)
    • 但是对Todos中的每一条Todo状态更改并不会被监听(不会监听下一级变化)
    • change的object属性代表改变之后的状态
    constructor() {
        observe(this.Todos, change => {
            console.log(change,'this.Todos, change')
        })
    }
    

    MobX 提供了 decorator 的修饰器

    其只可以修饰类和类成员

    MobX 为了简化 API 让 @observable 能识别当前是被普通函数调用的还是被当作修饰器调用的,如果是修饰器(@)就自动识别变量类型

    spy

    用法:
    spy(listener) 注册一个全局间谍监听器,用来监听所有 MobX 中的事件。 它类似于同时在所有的 observable 上附加了一个 observe 监听器,而且还通知关于运行中的事务/反应和计算。

    spy(event => {
        console.log(event,'spy-event')
    });
    

    computed

    什么是 computed ?

    • 一般理解为对可观察数据做出的响应

    • 多个可观察数据组合成一个可观察数据

    import {observable, computed, autorun} from "mobx";
    
    class Store {
        @observable 
        price = 6;
        @observable 
        amount = 3;
    }
    const store = new Store()
    var total = computed(()=>{
        return store.price * store.amount;
    })
    
    total.observe((change)=>{
        console.log(total,'computed---------',change)
    })
    
    store.price = 9;
    

    简而言之,你有一个值,该值的结果依赖于其他被观察的值,并且该值也需要被 obserable,那么就使用computed。

    autorun

    什么是 autorun ?

    另一个响应 state 的 api 便是 autorun 。和 computed 类似,每当依赖的值改变时,其都会改变。不同的是, autorun 没有了 computed 的优化(当然,依赖值未改变的情况下也不会重新运行,但不会被自动回收)。因此在使用场景来说, autorun 通常用来执行一些有副作用的。例如打印日志,更新 UI 等等。

    官方定义:

    当你想创建一个响应式函数,而该函数本身永远不会有观察者时,可以使用 mobx.autorun。 这通常是当你需要从反应式代码桥接到命令式代码的情况,例如打印日志、持久化或者更新UI的代码。 当使用 autorun 时,所提供的函数总是立即被触发一次,然后每次它的依赖关系改变时会再次被触发
    相比之下, computed(function) 创建的函数只有当它有自己的观察者时才会重新计算,否则它的值会被认为是不相关的 。 经验法则:如果你有一个函数应该自动运行,但不会产生一个新的值,请使用autorun。 其余情况都应该使用 computed。 Autoruns 是关于 启动效果 (initiating effects) 的 ,而不是产生新的值。 如果字符串作为第一个参数传递给 autorun ,它将被用作调试名。

    简而言之:自动追踪其所引用的可观察数据,并在数据发生变化时重新触发

    假如你观察了一个数组,你想根据数组的长度变化作出反应,在不使用 computed 时,代码是这样的

    var numbers = observable([1, 2, 3]);
    autorun(() => console.log(numbers.length));
    // 输出 '3'
    numbers.push(4);
    // 输出 '4'
    numbers[0] = 0;
    // 输出 '4'
    

    使用 computed 最后一个改变数组内元素内容的改变就不会被触发

    const Mobx = require("mobx");
    const { observable, autorun, computed } = Mobx;
    var numbers = observable([1, 2, 3]);
    var sum = computed(() => numbers.length);
    autorun(() => console.log(sum.get()));
    // 输出 '3'
    numbers.push(4);
    // 输出 '4'
    numbers[0] = 1;
    

    总结:

    • computed 可以当作新的可观察数据看待
    • autorun 引用的可观察数据发生的变化 无论是否修改数据都会先行执行一次

      如果你想响应式的产生一个可以被其它 observer 使用的值,请使用 @computed,如果你不想产生一个新值,而想要达到一个效果(比如上文提到的 打印日志、持久化或者更新UI的代码,请使用 autorun。

    when

    提供了条件执行逻辑

    class Store {
        @observable 
        bool = false;
    }
    const store = new Store()
    when(()=>store.bool, ()=>console.log('when~'));
    console.log('-----')
    store.bool = true
    // -----
    // when~
    

    如果一开始 bool 就是 true 那 when 就会立即执行

    action

    什么是 action ?

    action 是任何用来修改状态的东西

    在 MobX 中,对于 store 对象中可观察的属性值,在他们改变的时候则会触发观察监听的函数,这里注意两点:

    1. 该属性必须是定义的可观察属性(@observable)
    2. 它的值必须发生改变(和原值是不等的)

    何时使用action

    应该永远只对修改状态的函数使用 action。

    只执行查找,过滤器等函数不应该被标记为动作,以允许 MobX 跟踪它们的调用。

    对于 todolist 中的 demo 来讲

    @action
    createTodo(title:string,content:string) {
        this.Todos.unshift(new Todo(title,content));
    }
    
    @action
    createTodo(Todo:IINSTodo) {
        this.Todos.remove(Todo)
    }
    

    createTodo 和 createTodo 会将 被观察的 Todos 改变


    Intercept & Observe

    MobX 还提供了很多好用的方法,例如上面代码中的 this.Todos.remove(Todo) 的remove方法可以直接从数组中删除某元素,不用遍历查找再删除


    定义数据存储

    可以通过在应用中传递属性到组件树中或使用 mobx-react 包中的 Provider 和 inject 来分发 UI 状态 store。

    ProviderInject

    Provider 是一个组件,可以使用 react 上下文机制将 store (其他东西)传递给子组件。如果你不希望显示传递多层组件请使用 provider

    inject 可以获得 store 它是一个更高阶的组件,它接受一个字符串列表并使这些存储可用于被包装的组件。


    MobX 学习参考:

    https://github.com/ckinmind/mobx-share


    React Native 基础了解

    常用标签(组件)篇

    使用: import { View, Text, TextInput, TouchableOpacity } from "react-native";

    View

    相当于 html 的 div,块容器

    Image

    图片展示组件,常用属性如下:

    source

    source={{uri: "XXX"}}
    加载网络图片, 必须设置宽和高才能展示。在展示图片前,最好判断XXX是否存在

    source={require("XXX")}
    加载本地图片,XXX为本地图片相对地址

    TouchableOpacity

    用于写按钮的组件。常用属性如下:(此组件与TouchableHighlight的区别在于并没有额外的颜色变化,更适于一般场景)

    • activeOpacity
      指定封装的视图在被触摸操作激活时以多少不透明度显示(通常在 0 到 1 之间)

    • onPress
      类似平时写的 onClick

    TouchableHighlight

    用于写按钮的组件,常用属性如下:

    • activeOpacity
      指定封装的视图在被触摸操作激活时以多少不透明度显示(通常在 0 到 1 之间)

    • underlayColor
      有触摸操作时显示出来的底层的颜色

    • onPress
      类似平时写的 onClick

    Text

    显示文字的组件 ( 文字不能直接写在 View 中要嵌套 Text

    <View><Text> 要显示的文字 </Text></View>
    
    • ellipsizeMode

      取值('head', 'middle', 'tail', 'clip')

      • head
        从文本的开头进行截断,并在文本的开头添加省略号,例如:…xyz。
      • middle
        从文本的中间进行截断,并在文本的中间添加省略号,例如:ab…yz。
      • tail
        从文本的末尾进行截断,并在文本的末尾添加省略号,例如:abcd…。
      • clip
        文本的末尾显示不下的内容会被截断,并且不添加省略号,clip只适用于iOS平台。

    • numberOfLines
      限制最多显示的行数

    • onPress
      类似平时写的 onClick

    TextInput

    输入框组件

    • value

    • onChangeText

    • underlineColorAndroid="transparent"
      TextInput在安卓上默认有一个底边框,同时会有一些padding。如果要想使其看起来和iOS上尽量一致,则需要设置padding: 0,同时设置underlineColorAndroid="transparent"来去掉底边框

    • placeholder
      提示文本

    • placeholderTextColor
      提示文本颜色

    • onBlur
      当文本框失去焦点的时候调用此回调函数。

    • onFocus
      当文本框获得焦点的时候调用此回调函数。

    ScrollView

    • horizontal
      当此属性为true的时候,所有的子视图会在水平方向上排成一行,而不是默认的在垂直方向上排成一列。默认值为false。

    • showsHorizontalScrollIndicator
      当此属性为true的时候,显示一个水平方向的滚动条。

    StyleSheet

    样式定义 StyleSheet.create

    style的写法基本就与正常的css相同,只不过用中划线的css名字改用驼峰式写法
    例如: margin-top 改为 marginTop

    Dimensions

    获取屏幕尺寸 :
    Dimensions.get('window').height
    Dimensions.get('window').width

    布局

    flex布局

    路由

    在 App.ts 中定义路由

    import { NativeRouter, Route } from "react-router-native";
    ...
    <NativeRouter>
        <Route exact={true} path="/" component={index} />
        <Route path="/Content" component={Content} />
    </NativeRouter>
    

    其中 exact 是 Route 下的一条属性,一般而言,react 路由会匹配所有匹配到的路由组价,exact 能够使得路由的匹配更严格一些。

    • exact 的值为 bool 型,为 true 是表示严格匹配,为 false 时为正常匹配。
    • 如在 exact 为 true 时,' /link ' 与 ' / ' 是不匹配的,但是在 false 的情况下它们又是匹配的。

    注意: react-router 还分为浏览器端(h5)和 rn应用端

    API

    <BrowserRouter>
    basename: string
    getUserConfirmation: func
    forceRefresh: bool
    keyLength: number
    children: node
    <HashRouter>
    basename: string
    getUserConfirmation: func
    hashType: string
    children: node
    <Link>
    to: string
    to: object
    replace: bool
    innerRef: function
    innerRef: RefObject
    others
    <NavLink>
    activeClassName: string
    activeStyle: object
    exact: bool
    strict: bool
    isActive: func
    location: object
    aria-current: string
    <Prompt>
    <MemoryRouter>
    initialEntries: array
    initialIndex: number
    getUserConfirmation: func
    keyLength: number
    children: node
    <Redirect>
    to: string
    to: object
    push: bool
    from: string
    exact: bool
    strict: bool
    <Route>
    Route render methods
    Route props
    component
    render: func
    children: func
    path: string | string[]
    exact: bool
    strict: bool
    location: object
    sensitive: bool
    <Router>
    history: object
    children: node
    <StaticRouter>
    basename: string
    location: string
    location: object
    context: object
    children: node
    <Switch>
    location: object
    children: node
    history
    history is mutable
    location
    match
    null matches
    matchPath
    pathname
    props
    withRouter
    Component.WrappedComponent
    wrappedComponentRef: func
    

    例子:

    import { HashRouter as Router, Route } from "react-router-dom";
    ...
    <Router>
        <div style={{ display: "flex", height: "100%" }}>
            <Route exact={true} path="/" component={xxx} />
            ...
        </div>
    </Router>
    

    API:

    <BackButton>
    children
    <DeepLinking>
    <Link>
    to: string
    to: object
    replace: bool
    component: func
    <NativeRouter>
    getUserConfirmation: func
    keyLength: number
    children: node
    <MemoryRouter>
    initialEntries: array
    initialIndex: number
    getUserConfirmation: func
    keyLength: number
    children: node
    <Redirect>
    to: string
    to: object
    push: bool
    from: string
    exact: bool
    strict: bool
    <Route>
    Route render methods
    Route props
    component
    render: func
    children: func
    path: string | string[]
    exact: bool
    strict: bool
    location: object
    sensitive: bool
    <Router>
    history: object
    children: node
    <StaticRouter>
    basename: string
    location: string
    location: object
    context: object
    children: node
    <Switch>
    location: object
    children: node
    history
    history is mutable
    location
    match
    null matches
    matchPath
    pathname
    props
    withRouter
    Component.WrappedComponent
    wrappedComponentRef: func
    

    例子:

    import { NativeRouter, Route } from "react-router-native";
    ...
    <NativeRouter>
        <Route exact={true} path="/" component={xxx} />
        <Route path="/xxx" component={xxx} />
    </NativeRouter>
    

    参考:

    react-router 文档

    REACT ROUTER <- 这个讲的很详细,上述的API在其中有代码演示


    更多参考: react native 中文网


    相关文章

      网友评论

        本文标题:初识 MobX + React-Native + React R

        本文链接:https://www.haomeiwen.com/subject/bjxbmqtx.html