react-native MobX随了我喜欢的编程风格

MobX 给你久违已久的编程风格


react-native 指令编译运行

总是忘记几个命令这里就专门记录下来。<我在Mac air 终端执行>
查看当前可用的设备/模拟器的列表:xcrun simctl list devices

指定模拟器平台编译运行:

react-native run-ios --simulator "iPhone Xʀ"


MobX 在react-native使用

Mobx使用前错误纠正

No bundle URL present.
在这里插入图片描述

No bundle URL present. Make sure you’re running apackager server …

我的成功解决方案: rm -r ./ios/build && react-native run-ios --simulator "iPhone Xs"

SyntaxError: Support for the experimental syntax ‘decorators-legacy’ isn’t currently enabled
在这里插入图片描述

SyntaxError: Support for the experimental syntax ‘decorators-legacy’ isn’t currently enabled

~~我的成功解决方案``:安装"@babel/plugin-proposal-decorators": "^7.4.4"
并配置,新建文件.babelrc 参考overflow信息

//.babelrc

{
  "plugins": [["@babel/plugin-proposal-decorators", { "legacy": true }]]
}

null is not an object (evaluating ‘_RNGestureHandlreModule.default.Direction’)
出现这个错误的原因是,我在项目中配个导航组件React Navigation
在这里插入图片描述
出错环境 Mac Air

reactreact-nativereact-navigationreact-native-gesture-handlerreact-native-reanimated
“16.8.3”“0.60.4”“^3.11.1”“^1.3.0”“^1.1.0”

找了好久,没得解决方法

最后没办法我就换了react-native的Version号,好像说是0.60.4版本在这方面是个bug,还没解决!!

reactreact-nativereact-navigationreact-native-gesture-handlerreact-native-reanimatedmobxmobx-react@babel/plugin-proposal-decorators
“16.8.3”“0.59.9”“^3.11.1”“^1.3.0”“^1.1.0”“^5.13.0”“^6.1.1”“^7.4.4”

配置完了,页面的导航,于是写个简单demo。先看首页和源码:附源码
在这里插入图片描述
在这里插入图片描述

import React, { Component } from "react";
import { View, Text, Platform, StatusBar } from "react-native";
import { observer, inject } from "mobx-react";
import { observable, action, autorun } from "mobx";
import { Label, Button } from "teaset";

const instructions = Platform.select({
  ios: "Press Cmd+R to reload,\n" + "Cmd+D or shake for dev menu",
  android:
    "Double tap R on your keyboard to reload,\n" +
    "Shake or press menu button for dev menu"
});
const dsposer = autorun(Num => console.log("打印监听的Num数:", Num));

@observer
export default class HomePage extends Component {
  static navigationOptions = {
    title: "首页",
    headerBackTitle: " ", //下一级页面就不会显示 "首页" 二字了
    headerStyle: { backgroundColor: "#f4511e" },
    headerTintColor: "#FFF",
    headerTitleStyle: { fontWeight: "bold", fontSize: 20 }
  };

  @observable
  Num = 0;

  componentWillMount() {
    StatusBar.setBarStyle("light-content");
    console.log("打印监听 componentWillMount ");
  }

  componentDidMount() {
    console.log("打印监听 componentDidMount ");
  }

  componentWillUpdate() {
    console.log("打印监听 componentWillUpdate ");
  }

  componentDidUpdate() {
    console.log("打印监听 componentDidUpdate ");
  }

  componentWillReceiveProps() {
    console.log("打印监听 componentWillReceiveProps ");
  }

  //   shouldComponentUpdate() {
  //     console.log("打印监听 shouldComponentUpdate ");
  //   }

  render() {
    return (
      <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
        <Text>{instructions}</Text>
        <Button
          type="primary"
          size="lg"
          title="跳转到二维码图片页面"
          onPress={this.gotoGeneratorQr}
          titleStyle={{ color: "#333" }}
          style={{ marginTop: 10, backgroundColor: "#fcf8e3" }}
        />
        <View
          style={{
            flexDirection: "row",
            height: 45,
            justifyContent: "center",
            marginTop: 15
          }}
        >
          <Button
            type="danger"
            size="sm"
            title="数量减"
            onPress={this.decreaseNum}
            titleStyle={{ color: "#333" }}
            style={{
              marginHorizontal: 10,
              backgroundColor: "#fcf8e3",
              width: 80
            }}
          />
          <Label type="title" size="xl" text={this.Num} />
          <Button
            type="danger"
            size="sm"
            title="数量增"
            onPress={this.increaseNum}
            titleStyle={{ color: "#333" }}
            style={{
              marginHorizontal: 10,
              backgroundColor: "#fcf8e3",
              width: 80
            }}
          />
        </View>
      </View>
    );
  }

  gotoGeneratorQr = () => {
    this.props.navigation.navigate("GeneratorQr");
  };

  @action
  actionDecreaseNum() {
    this.Num--;
  }
  @action.bound
  actionIncreaseNum() {
    this.Num++;
  }

  decreaseNum = () => {
    this.actionDecreaseNum();
  };
  increaseNum = () => {
    this.actionIncreaseNum();
  };
}


看源码,这个页面功能使用MobX比较简单。

生命周期

分析使用MobX之后的react-native的生命周期有什么变化!
在这里插入图片描述
由上图来说,如果项目中解注释生命周期方法shouldComponentUpdate运行报错:
在这里插入图片描述
注释了这个方法之后,可以看到打印结果来看生命周期:
第一次执行结果,
在这里插入图片描述
点击按钮“数量增”,改变状态,看MobX这个时候会触发那些生命周期。
在这里插入图片描述
发现,MobX状态被改变之后,会再次触发生命周期方法componentWillUpdatecomponentDidUpdate 。也就是说,有没有方法shouldComponentUpdate的区别!
官方文档上解释

observer

observer函数/装饰器可以用来将 React 组件转变成响应式组件。
在这里插入图片描述

observable 、action、computed、autorun、when

然后源码中第25、26行,@observable装饰器可以在 ES7类属性中使用,将其转换成可观察的,即109行、111行方法中进行属性Num的处理。Num的变化会被立即观察到并更新。由此,我们可以看到点击数量增和数量减按钮,可以看到预期的效果。

现对源码稍作处理,在源码分析处理函数,actionDecreaseNumactionIncreaseNum
在这里插入图片描述
再做运行点击,发现“数量递增”按钮不能使用了。为什么呢?了解一下Action注解关键字的作用先。
action装饰器/函数遵循 javascript 中标准的绑定规则
它是一种动作,用来修改状态的动作。因此看到递减的按钮调用actionDecreaseNum方法依然可以达到数量递减的效果,所以使用@action它就充当了让方法具备使数字递减的动作。但是我们又能发现,即使不使用action也能实现递增和递减的效果,为什么要使用它呢?因为动作可以有助于更好的组织代码。而且官方还说,应该永远只对修改状态的函数使用动作。
回到未解决的问题上来,发现“数量递增”按钮不能使用了,为什么?
而且有趣的是,还有一个action.bound。和action有什么区别?
数量递增按钮不能用了,原因是不能和箭头函数一起使用;箭头函数已经是绑定过的,已经绑定过的则不能重新绑定!
action和action.bound区别是,action.bound 可以用来自动地将动作绑定到目标对象。不需要一个name参数,名称将始终基于动作绑定的属性。如下图,
在这里插入图片描述
从官方文档上看,有几个关键字段
在这里插入图片描述
不要把 computed 和 autorun 搞混。它们都是响应式调用的表达式,但是,如果你想响应式的产生一个可以被其它 observer 使用的值,请使用 @computed,如果你不想产生一个新值,而想要达到一个效果,请使用 autorun。还有使用上的区别:
在生命周期方法componentDidMount中加入响应方法autorun做监听
在这里插入图片描述
会发现,每次点击,且使Num状态发生变化之后,都会有立即响应打印"打印监听的Num数:xx"!但是,如果使用@computed
在这里插入图片描述
每次点击,即使Num状态发生变化,total方法中也不会有立即响应打印!除非UI中被调用。
而使用关键字when的时候,会有立即响应。但是是有条件的,第一个参数中,要用到 @observable进行修饰 的属性变量。
在这里插入图片描述
比如图中,如果变量isVisiable在构造方法中定义,即使调用并改变了某个别的使用 @observable进行修饰 的属性变量,也不会触发调用方法isVisableLog,除非,isVisiable使用@observable进行修饰。在when使用上,我们可以看到它可以起到一个简单拦截作用,在拦截中再做二次数据处理。

Provider、inject

使用关键字Providerinject,实现下边的变化
在这里插入图片描述
看到没,UI内容中多了一个加载动画,加载动画文字下面的字体发生了变化。在源码中我做了如下处理:
在栈组件(app.js)之前新增了一个中间过渡的组件——MiddleWare.js。过渡组件中引入了关键字Provider——可以用来使用 React 的context机制来传递 store 给子组件。因此,我们可以在子组件中直接使用一些嵌入的属性。比如:引入 color={"#FFB90F"} 使用方式——this.props.color ;引入{...store} 使用方式——this.props.activeIndicator.showindicator() 。具体使用方式,往下瞅:

///MiddleWare.js
import React, { Component } from "react";
import { View, Text } from "react-native";
import { Provider } from "mobx-react";
import NewApp from "./app";
import store from "./src/base/Store";

export default class MiddleWare extends Component {
  render() {
    return (
      <View style={{ flex: 1 }}>
        <Provider color={"#FFB90F"} {...store}>
          <NewApp />
        </Provider>
      </View>
    );
  }
}

其中,Store.js 中放入了一个加载动画

///Store.js
import activeIndicator from "./ActiveIndicator";
export default {
  activeIndicator
};

加载动画组件:
在这里插入图片描述
配置上面都介绍过了,怎么使用?
使用点有两个,先注解引入,然后使用。

引入注解

在这里插入图片描述

使用注入的内容

在这里插入图片描述
然后就有上面显示的效果了,字体颜色能够修改,加载动画也在执行!
但是,使用过程中还是有些需要注意的。目前我发现的有俩!
第一, 由于我使用的mobx-react版本,最新版本有bug,作者还没解决。所以需要返回到低一点的稳定版本使用。报错是,Expected a constructor
在这里插入图片描述
参考解决方案 最终修改下mobx-react版本号。

reactreact-nativereact-navigationreact-native-gesture-handlerreact-native-reanimatedmobxmobx-react@babel/plugin-proposal-decorators
“16.8.3”“0.59.9”“^3.11.1”“^1.3.0”“^1.1.0”“^5.13.0”“^5.4.3”“^7.4.4”

第二, 只针对color={"#FFB90F"}这类属性。在使用Redux的时候,写了<Provider color={"#FFB90F"} {...store}>之后根本不用在使用的地方添加注解@inject("color", "activeIndicator")来声明color。但是在MobX中不使用注解进行声明,调用this.props.color还是没用的!

重点

我自定义一个组件,仅仅在生命周期componentDidMount中进行打印一下普通内容
在这里插入图片描述
然后在HomePage.js中通过注解符号 @ 引入,
在这里插入图片描述
运行结果,出乎意料,竟然执行到了那两行打印 :
在这里插入图片描述
Using HOC via es7 Decorators
对于高阶组件在这里使用,我多啰嗦两句,如果按照下面这样直接使用
在这里插入图片描述
在这里插入图片描述
你会发现一个奇怪的结果,当然我正是想要使用这个奇怪的结果,来解释高阶组件在这里是如何使用的!奇怪结果:"首页"白色标题文字和整个深橘色背景都没了。

在这里插入图片描述
我的猜测就是HomePage.js通过添加注解@NetInfoDecorator,使得由原本的继承方式class HomePage extends Component 改换成了 class HomePage extends NetInfoDecorator。为了验证我的猜想,在NetInfoDecorator中加入配置标题的style
在这里插入图片描述
执行,结果和我的猜想是一样的
在这里插入图片描述
因此得出结论:HomePage.js通过添加注解@NetInfoDecorator,使得由原本的继承方式class HomePage extends Component 改换成了 class HomePage extends NetInfoDecorator。并且适用于更广泛的应用,比如 我们可以在生命周期中预先去做统一的处理、监听网络连接、打印一些内容等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值