RN使用mobx状态管理库

RN引入mobx状态管理库,本文根据自己在项目中真实使用场景讲述如何快速接入mobx

mobx介绍

Mobx和Redux都是应用于React工程优秀的状态管理库,可以解决我们跨页面跨组件间通信问题。不过理念有所不同,Redux推崇状态树的概念,认为一个应用中只应该存在一个状态库,通过Providerstore挂载到视图顶层,使用的组件通过connect方式用props来访问需要的状态属性。而Mobx则并不强调状态树的概念,而是可以各自模块使用各自的状态库,不过也同样可以通过Provider将状态挂载到顶层视图,在消费组件中通过inject获取到props状态。 具体差异可以到官网上了解

mobx引入

安装依赖

我们引入两个库mobxreact-mobx-lite(不使用react-mobx,因为mobx+mobx-react-litebundle体积增加67K,而mobx+mobx-reactbundle体积增加80K,当然,redux+react-redux的bundle体积增加27K)

yarn mobx react-mobx-lite

依赖添加后,package.json中的dependencies如下

  "dependencies": {
    "mobx": "^6.3.8",
    "mobx-react-lite": "^3.2.2",
    "react": "17.0.2",
    "react-native": "0.66.3"
  },

效果预览

在这里插入图片描述

项目中使用

在定义store的方式上基本都是一致的,不同的是使用方式,可以按使用store是否共享、使用storeComponent组件还是函数组件、store是否在顶层组件树上挂载来进行区分.
当然,不论项目中如何使用,定义store的方式都是一样的

  • 定义store:通过mobx库常用的observableactioncomputed定义观察属性和修改属性的方法,在 6.x版本之后,需要通过makeAutoObservablemakeObservable声明观察对象,可以参考一篇博文:mobx升级到6后组件不刷新
import {action, makeObservable, observable, computed} from 'mobx';
export class CountStore {
  count = 0; // 数量
  price = 10; // 单价
  constructor() {
    // makeAutoObservable(this);
    makeObservable(this, {
      count: observable,
      setCount: action,
      totalPrice: computed,
    });
  }

  get totalPrice() {
    //总价,为了模拟因为count变化导致总价变化的情况,使用computed,有点类似vue中的computed计算属性
    return this.count * price;
  }

  setCount(count) {
    if (count >= 0) {
      this.count = count;
    }
  }
}
  • CountComponent组件是一个公共的组件,为了更快捷地示范以下store应用场景而封装的

常见使用-局部共享store

observable+action+observer

  1. 创建store实例:通过new Store()创建出一个store的实例
  2. 消费store:通过mobx-react-lite库的observer定义组件

store消费代码:

import React from 'react';
import {observer} from 'mobx-react';
import {CountStore} from './store/countStore';
import {CountComponent} from './common/components/CountComponent';
const countModel = new CountStore();

// 函数组件方式
export const CountMobxPage = observer(props => {
  return (
    <CountComponent
      title={'CountMobxPage'}
      count={countModel.count}
      price={countModel.price}
      totalPrice={countModel.totalPrice}
      onPressDescrease={() => countModel.setCount(countModel.count - 1)}
      onPressInscrease={() => countModel.setCount(countModel.count + 1)}
    />
  );
});
// class组件方式
export const CountMobxClassPage = observer(
  class extends React.Component {
    render() {
      return (
        <CountComponent
          title={'CountMobxClassPage'}
          count={countModel.count}
          price={countModel.price}
          totalPrice={countModel.totalPrice}
          onPressDescrease={() => countModel.setCount(countModel.count - 1)}
          onPressInscrease={() => countModel.setCount(countModel.count + 1)}
        />
      );
    }
  },
);

// 使用代码
/** 其他代码...**/
render(){
  return(
    <>
      <CountMobxPage/>
      <CountMobxClassPage/>
    </>
  )

}

独立store(类似state的效果)

使用独立store时,store的生命周期和组件声明周期一致,在组件销毁时,store也会被系统回收销毁,不会造成内存污染
在使用独立store时,函数组件和class组件的方式差异较大。

函数组件独立使用store

需要结合React.useRef使用,这样才能进行实例隔离,同时需要注意的是,不能直接使用useRef(new Store()),这样会造成不断创建一个新的store实例,虽然这不会替换掉refcurrent,但是这是无意义的消耗

export const CountMobxSelfPage = observer(props => {
  const mobxRef = React.useRef(null);
  if (!mobxRef.current) {
    mobxRef.current = new CountStore();
  }
  return (
    <CountComponent
      title={'CountMobxSelfPage——独立store——函数组件'}
      count={mobxRef.current.count}
      price={mobxRef.current.price}
      totalPrice={mobxRef.current.totalPrice}
      onPressDescrease={() =>
        mobxRef.current.setCount(mobxRef.current.count - 1)
      }
      onPressInscrease={() =>
        mobxRef.current.setCount(mobxRef.current.count + 1)
      }
    />
  );
});
class组件独立使用store

constructor实例化class组件时,将store实例化

export const CountMobxSelfClassPage = observer(
  class extends React.Component {
    constructor(props) {
      super(props);
      this.store = new CountStore();
    }
    render() {
      return (
        <CountComponent
          title={'CountMobxSelfClassPage--独立store-class组件'}
          count={this.store.count}
          price={this.store.price}
          totalPrice={this.store.totalPrice}
          onPressDescrease={() => this.store.setCount(this.store.count - 1)}
          onPressInscrease={() => this.store.setCount(this.store.count + 1)}
        />
      );
    }
  },
);

通过Providerinject共享store

这种方式和redux的状态树理念有些类似,都是通过Provider来共享状态库,不过mobx可以有多个store,并且inject消费的类如果要修改store的属性,应该将store作为props传递给要使用组件,将action的方法通过props传递给子组件后调用并不能影响视图的更新。

const providerStore = new CountStore();
export const MobxPropsPage = props => {
  return (
    <Provider store={providerStore}>
      <Text>MobxPropsPage-使用Provider和inject方式使用store库</Text>
      <MobxPropsUsePage />
      <MobxPropsUseClassPage />
    </Provider>
  );
};

const MobxPropsUsePage = inject('store')(
  observer(props => {
    return (
      <CountComponent
        title={'MobxPropsUsePage--共享store-class组件'}
        count={props.store.count}
        price={props.store.price}
        totalPrice={props.store.totalPrice}
        onPressDescrease={() => props.store.setCount(props.store.count - 1)}
        onPressInscrease={() => props.store.setCount(props.store.count + 1)}
      />
    );
  }),
);

const MobxPropsUseClassPage = inject('store')(
  observer(
    class extends React.Component {
      render() {
        return (
          <CountComponent
            title={'MobxPropsUseClassPage--共享store-函数组件'}
            count={this.props.store.count}
            price={this.props.store.price}
            totalPrice={this.props.store.totalPrice}
            onPressDescrease={() =>
              this.props.store.setCount(this.props.store.count - 1)
            }
            onPressInscrease={() =>
              this.props.store.setCount(this.props.store.count + 1)
            }
          />
        );
      }
    },
  ),
);

其他

CountComponent组件代码

import {View, Text, TouchableOpacity} from 'react-native';
import {commonStyles} from '../styles/commonStyles';
import {PropTypes} from 'prop-types';

export function CountComponent(props) {
  const {title, count, price, totalPrice, onPressDescrease, onPressInscrease} =
    props;
  return (
    <View style={commonStyles.contain}>
      <Text style={commonStyles.titleText}>{title}</Text>
      <View style={commonStyles.textContain}>
        <Text>数量:</Text>
        <TouchableOpacity onPress={() => onPressDescrease()}>
          <Text style={commonStyles.text}>-</Text>
        </TouchableOpacity>
        <Text style={commonStyles.countText}>{count}</Text>
        <TouchableOpacity onPress={() => onPressInscrease()}>
          <Text style={commonStyles.text}>+</Text>
        </TouchableOpacity>
      </View>
      <View style={commonStyles.priceContain}>
        <Text style={commonStyles.price}>{`单价:${price}`}</Text>
        <Text style={commonStyles.totalText}>{`总价:${totalPrice}`}</Text>
      </View>
    </View>
  );
}

CountComponent.propTypes = {
  title: PropTypes.string,
  count: PropTypes.number,
  price: PropTypes.number,
  totalPrice: PropTypes.number,
  onPressDescrease: PropTypes.func,
  onPressInscrease: PropTypes.func,
};

commonStyle样式代码

import {StyleSheet} from 'react-native';

export const commonStyles = StyleSheet.create({
  contain: {
    borderBottomColor: '#CCC',
    borderBottomWidth: 1,
    paddingHorizontal: 15,
    paddingVertical: 5,
  },
  viewContain: {flexDirection: 'row', alignItems: 'center'},
  titleText: {fontSize: 17, fontWeight: 'bold', color: '#333'},
  text: {
    fontSize: 16,
    backgroundColor: '#FFF',
    lineHeight: 22,
    paddingHorizontal: 40,
  },
  countText: {
    fontSize: 16,
    color: '#981122',
    paddingHorizontal: 20,
    minWidth: 40,
  },
  textContain: {padding: 5, alignItems: 'center', flexDirection: 'row'},
  priceText: {fontSize: 15},
  totalText: {marginLeft: 20, fontSize: 15, color: '#222', fontWeight: 'bold'},
  priceContain: {margin: 10, flexDirection: 'row', alignItems: 'center'},
});
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值