ホームページ >ウェブフロントエンド >jsチュートリアル >React-Native+MobxでモールAPPを実装
今回は、React-Native+Mobx でモール APP を実装するための 注意事項 について説明します。以下は実際的なケースです。
私は最近、WeChat ミニプログラムを学習しています。その過程で、wxapp-mall を見ました。 この WeChat アプレット プロジェクトは非常に優れており、UI も非常に小さく新鮮だと思ったので、ソース コードを確認するためにクローンを作成したところ、複雑ではないことがわかり、本当に驚きました。豊富な機能を実装するためにあまり多くのコードを使用しないので、このような小さなプロジェクトを作成するのに反応ネイティブを使用するのは難しいのではないかと考えました。さらに、一連のコードを作成すると Android と iOS の両方を実行できます (同じことが当てはまります)。小さなプログラム...)、ぜひ書いてみてはいかがでしょうか?この考えを念頭に置いて、私は直接、 React-native init プロジェクトを書いてみましょう (๑•̀ㅂ•́)و✧技術的なフレームワークとコンポーネント
Mobx を使用する理由?
Mobx は、react-redux よりもシンプルで、すぐに開始できるスケーラブルな状態管理ツールです。この小規模プロジェクトでは、バックグラウンド サービス インターフェイスがないため、実装をシミュレートするためにすべてのローカルの偽データが使用されます。 アイテムを参照 =>カートに追加=>チェックアウト=>カートをクリア=>アイテムを元の状態に戻す このようなプロセスでは、Mobx を使用してすべてのデータと商品ステータス (商品が選択されているかどうか、ショッピング カートに追加されているかどうか) を管理するため、すべてのページでデータを共有し、商品のステータスを変更したり、データや商品の状態を変更したりできます。ページ間の商品のステータスは同期して更新されます。具体的には、Mobx を使用してこのプロセスを実装する方法について、それを使用した私の経験と遭遇したいくつかの落とし穴を以下で共有します。スタート
最初の反応ネイティブ プロジェクトを初期化し、yarn または npm を使用してすべての依存関係とコンポーネントをインストールします。 Mobxを使用するとES7のデコレーターが使用されるため、インストールする必要があります babel-plugin-transform-decorators-legacy プラグインを開き、.babelrc ファイルの下にコンテンツを追加します。りー
プロジェクトの構造
{ "presets": ["react-native"], "plugins": ["transform-decorators-legacy"] }Root.js ファイルでは、react-navigation の設定と使用法については、公式ドキュメントとこのブログを参照してください。これらの 2 つの記事で、react-navigation に関する質問に対する答えが見つかりました。関連する React-Navigation 設定、使用方法、プロジェクト
主にMobxについて話しましょう
1. データの保存と取得
これらは偽のデータを使用してシミュレートされ、実装されます。最初に、偽のデータのデータ構造を次のように記述します。 Mobx フォルダー内の store.js は、主にアプリで使用されるすべての製品のデータを保存および管理し、コンポーネントから独立したテスト可能なユニットにロジックと状態を移動します。このユニットは各ページで使用できます。どこにでもあるよすごい
ここでは、RootStore を使用してすべてのストアをインスタンス化します (ショッピング カート、ホームページ、カテゴリ ページには独自のストアがあります)。 このようにして、ストアは RootStore を通じて管理および操作でき、相互に通信して参照を共有できるようになります。 次に、Mobx の @observable メソッドを使用してデータを保存します。これにより、データがオブザーバーに変わり、ユーザーがビューを操作してデータが変更されると、react-mobx が提供する @observer を使用してビューを自動的に更新できます。 、とても便利です。 さらに、Mobx の Rootstore を反応ネイティブ コンポーネントに挿入するには、mobx-react によって提供されるプロバイダーを介して実装する必要があります:|-- android |-- ios |-- node_modules |-- src |-- common // 公用组件 |-- img // 静态图片 |-- mobx // mobx store |-- newGoods.js // 首页新品数据 |-- cartGoods.js // 购物车数据 |-- categoryGoods.js // 分类页数据 |-- store.js // store仓库,管理数据状态 |-- scene |-- Cart // 购物车页面 |-- Category // 分类页 |-- Home // 首页 |-- ItemDetail // 商品信息页 |-- Mine // 我的页面 |-- Root.js // root.js主要内容是配置react-navigation(导航器) |-- index.js // 主入口Rootstore インスタンスをコンポーネント ツリーに挿入した後、コンポーネント内で this.props.rootStore を使用して直接取得できますか?
‘'不是的”,我们还需要在要用到Rootstore的组件里,要加点小玩意,在 HomeScreen.js (首页)中这么写:
import { inject, observer } from 'mobx-react' @inject('rootStore') // 缓存rootStore,也就是在Root.js注入的 @observerexport default class HomeScreen extends Component { ...... }
加上了 @inject('rootStore') ,我们就可以愉快地使用 this.props.rootStore 来拿到我们想要的数据啦^_^ ,同样,在商品信息,分类页,购物车页面js下,也需要使用 @inject('rootStore') 来实现数据的获取,然后再一步步地把数据传到它们的子组件中。
2. 加入购物车的实现
在首页和分类页中,都可以点击跳转到商品信息页,然后再加入到购物车里
实现方法 :
在itemDetail.js下,也就是商品信息页面下,加入购物车的逻辑是这样子的:
addCart(value) { if(this.state.num == 0) { this.refs.toast.show('添加数量不能为0哦~') return; } // 加入购物车页面的列表上 // 点一次,购物车数据同步刷新 this.updateCartScreen(value) this.refs.toast.show('添加成功^_^请前往购物车页面查看') } // 同步更新购物车页面的数据 updateCartScreen (value) { let name = this.props.navigation.state.params.value.name; // 判断购物车页面是否存在同样名字的物品 let index; if(this.props.rootStore.CartStore) index = this.props.rootStore.CartStore.allDatas.data.findIndex(e => (e.name === name)) // 不存在 if(index == -1) { this.props.rootStore.CartStore.allDatas.data.push(value) // 加入CartStore里 // 并让购物车icon更新 let length = this.props.rootStore.CartStore.allDatas.data.length this.props.rootStore.CartStore.allDatas.data[length - 1].count += this.state.num} else { // 增加对应name的count this.props.rootStore.CartStore.allDatas.data[index].count += this.state.num }}
简单的说,先获取水果的名称name,然后再去判断Mobx的CartStore里面是否存在同样的名称的水果,如果有就增加对应name的数量count,如果没有,就往CartStore中增加数据,切换到购物车页面时,视图会同步刷新,看到已加入购物车的水果。
3.改变商品状态同步更新视图
当用户在购物车页面操作商品状态时,数据改变时,视图会跟着同步刷新。
例如,商品的增加数量,减少数据,选中状态,商品全选和商品删除,总价格都会随着商品的数量变化而变化。
图又来了~~
实现上面的功能,主要用到了Mobx提供的action方法,action是用来修改状态的,也就是用action来修改商品的各种状态(数量,选中状态...),这些action,我是写在 store.js 的 CartStore类 中的,下面贴出代码
// 购物车store class CartStore { @observable allDatas = {} constructor(data,rootStore) { this.allDatas = data this.rootStore = rootStore } //加 @action add(money) { this.allDatas.totalMoney += money } // 减 @action reduce(money) { this.allDatas.totalMoney -= money } // checkbox true @action checkTrue(money) { this.allDatas.totalMoney += money } // checkbox false @action checkFalse(money) { if(this.allDatas.totalMoney { this.allDatas.totalMoney += e.count * e.price})} else { this.allDatas.totalMoney = 0 }} // check全选 @action check() { // 所有checkbox为true时全选才为true let allTrue = this.allDatas.data.every(v => ( v.isSelected === true )) if(allTrue) { this.allDatas.isAllSelected = true }else { this.allDatas.isAllSelected = false }} // 删 @action delect(name) { this.allDatas.data = this.allDatas.data.filter (e => (e.name !== name )) } // 总价格 @computed get totalMoney() { let money = 0; let arr = this.allDatas.data.filter(e => (e.isSelected === true)) arr.forEach(e=> (money += e.price * e.count)) return money }}
所有修改商品状态的逻辑都在上面代码里面,其中,totalMoney是用了Mobx的@computed方法,totalMoney是依赖于CartStore的data数据,也就是商品数据,但data的值发生改变时,它会重新计算返回。如果了解vue的话,这个就相当于vue的计算属性。
4.结算商品
商品结算和清空购物车的逻辑都写在 CartCheckOut.js 里面,实现过程很简单,贴上代码吧:
// 付款 pay() { Alert.alert('您好',`总计:¥ ${this.props.mobx.CartStore.totalMoney}`, {text: '确认支付', onPress: () => this.clear()}, {text: '下次再买', onPress: () => null}],{ cancelable: false })} // 清空购物车 clear() { this.setState({visible: !this.state.visible}) setTimeout(()=>{ this.setState({ loadText: '支付成功!欢迎下次光临!' }) setTimeout(()=> { this.setState({ visible: false }, ()=>{ this.props.mobx.CartStore.allDatas.data = [] // 把所有商品count都变为0 this.props.mobx.NewGoodsStore.allDatas.data.forEach(e=> e.count = 0) this.props.mobx.categoryGoodsStore.allDatas.data.forEach( e => { e.detail.forEach(value => { value.count = 0 }) }) })},1500)},2000)}
这里主要用了setTimeout和一些方法来模拟实现 支付中 => 支付完成 => 清空购物车 => 还原商品状态。
好了,这个流程就搞定了,哈哈。
5.遇到的小坑
1.我写了一个数组的乱序方法,里面有用到 Array.isArray() 这个方法来判断是否为数组,但是,我用这个乱序函数时,想用来搞乱store里面的数组时,发现一直没有执行,觉得很奇怪。然后我直接用 Array.isArray() 这个方法来判断store里面的数组,返回的一直都是false。。。于是我就懵了。。。后来,我去看了Mobx官方文档,终于找到了答案。原来,store里面存放的数组,并不是真正的数组,而是 obverableArray ,如果要让 Array.isArray() 判断为true,就要在取到store的数组时,加个. slice() 方法,或者 Array.from() 都可以。
2.同样,也是obverableArray的问题。在购物车页面时,我用了FlatList来渲染购物车的item,起初,当我增加商品到购物车,发现购物车页面并没有刷新。有了上面的踩坑经验,我认为是obverableArray引起的,因为FlatList的data接收的是real Array,于是,我用这样的方法:
@computed get dataSource() { return this.props.rootStore.CartStore.allDatas.data.slice(); } ... <flatlist></flatlist>
于是,购物车视图就可以自动地刷新了,在官方文档上也有写到。
3.还有一个就是自己粗心造成的。我写完这个项目后,和朋友出去玩时,顺便发给朋友看看,他在删除商品时发现,从上往下删删不了,从下往上删就可以。后来我用模拟器测试也是如此,于是就去看看删除商品的逻辑,发现没有问题,再去看store的数据,发现也是可以同步更新的,只是视图没有更新,很神奇,于是我又在FlatList去找原因,终于,原因找到了,主要是在keyExtractor里面,用index是不可以的,要用name来作为key,因为我删除商品方法其实是根据name来删的,而不是index,所以用index来作为FlatList的Item的key时是会出现bug的。
_keyExtractor = (item,index)=> { // 千万别用index,不然在删购物车数据时,如果从第一个item开始删会产生节点渲染错乱的bug return item.name }
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
以上がReact-Native+MobxでモールAPPを実装の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。