React-Native+Mobx实现商城APP

这次给大家带来React-Native+Mobx实现商城APP,React-Native+Mobx实现商城APP的注意事项有哪些,下面就是实战案例,一起来看一下。

最近一直在学习微信小程序,在学习过程中,看到了 wxapp-mall 这个微信小程序的项目,觉得很不错,UI挺小清新的,便clone下来研究研究,在看源码过程中,发现并不复杂,用不多的代码来实现丰富的功能确实令我十分惊喜,于是,我就想,如果用react-native来做一个类似这种小项目难不难呢,何况,写一套代码还能同时跑android和ios(小程序也是。。。),要不写一个来玩玩?有了这个想法,我便直接 react-native init 一个project来写一下吧(๑•̀ㅂ•́)و✧

技术框架以及组件

react “16.0.0”

react-native “0.51.0”

mobx: “3.4.1”

mobx-react: “4.3.5”

react-navigation: “1.0.0-beta.21”

react-native-scrollable-tab-view: “0.8.0”

react-native-easy-toast: “1.0.9”

react-native-loading-spinner-overlay: “0.5.2”

为什么要用Mobx?

Mobx是可扩展的状态管理工具,比react-redux要简单,上手也比较快。在这个小项目中,因为没有后台服务接口,用的都是本地的假数据,为了模拟实现 浏览商品 =>加入购物车=>结账=>清空购物车=>还原商品原始状态 这么一个流程,便用Mobx来管理所有的数据以及商品的状态(有没有选中,有没有加入购物车),这样,所有的页面都可以共享数据以及改变商品的状态,页面之间的数据和商品状态都是同步更新的。具体用Mobx怎么来实现这流程,在下面会分享使用感受和遇到的一些小坑。

开始

先react-native init一个project,然后用yarn或者npm装好所有的依赖和组件。因为使用Mobx会用到ES7中装饰器,所以还要安装 babel-plugin-transform-decorators-legacy 这个插件,然后在.babelrc文件下添加一下内容即可。

{  "presets": ["react-native"],  "plugins": ["transform-decorators-legacy"]}

登录后复制

项目结构

|-- 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 // 主入口

登录后复制

在Root.js文件中,有关react-navigation的配置和使用方法可以参考下官方文档和这篇博客,里面都写得十分详细,有关react-navigation的疑问我都在这2篇文章中找到答案,在这里相关react-navigation配置,使用方法和项目里面页面布局,组件写法,在这里不打算细说,因为都比较简单,更多的是讨论Mobx实现功能的一些逻辑和方法, screen 文件夹下的组件都写有注释的(°ー°〃)

主要还是来聊聊Mobx吧

1.数据存储和获取

这些都是用假数据来模拟实现的,在最开始,先写好假数据的数据结构,例如:

"data": [{  "name": '那么大西瓜', "price": '2.0',  "image": require('../img/a11.png'),  "count": 0,  "isSelected": true },...]

登录后复制

在 Mobx 文件夹下的 store.js, 在这里主要是存储和管理app用到的所有商品的数据,将 逻辑 和 状态 从组件中移至一个独立的,可测试的单元,这个单元在每个页面下都可以用到

import { observable, computed, action } from 'mobx'import cartGoods from './cartGoods'import newGoods from './newGoods'import categoryGoods from './catetgoryGoods'/** * 根store * @class RootStore * CartStore 为购物车页面的数据 * NewGoodsStore 为首页的数据 * categoryGoodsStore 为分类页的数据 */class RootStore {  constructor() {  this.CartStore = new CartStore(cartGoods,this)  this.NewGoodsStore = new NewGoodsStore(newGoods,this)  this.categoryGoodsStore = new categoryGoodsStore(categoryGoods,this) }}Class CartStore{ @observable allDatas = {}  constructor(data,rootStore) {  this.allDatas = data  this.rootStore = rootStore  }}Class NewGoodsStore{ ...跟上面一样}Class categoryGoodsStore{ ...跟上面一样}// 返回RootStore实例 export default new RootStore()

登录后复制

这里用了 RootStore 来实例化所有了stores(购物车,首页,分类页分别拥有各自的store),

这样,可以通过RootStore 来管理和操作stores,从而实现它们之间的相互通信,共享引用。

其次,存储数据用了Mobx的@observable方法,就是把数据成为观察者,当用户操作视图,导致数据发生变化时,配合react-mobx提供的@observer可以自动更新视图,非常方便。

此外,为了把Mobx 的Rootstore注入到react-native的组件中,要通过 mobx-react 提供的 Provider 实现,在 Root.js 下,我是这么写的:

// 全局注册并注入mobx的Rootstore实例,首页新品,分类页,商品详情页,购物车页面都要用到storeimport {Provider} from 'mobx-react'// 获取store实例import store from './mobx/store' const Navigation = () => {  return (       )}

登录后复制

把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. 加入购物车的实现

在首页和分类页中,都可以点击跳转到商品信息页,然后再加入到购物车里

用React-Native+Mobx做一个迷你水果商城APP(附源码) 

实现方法 :

在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类 中的,下面贴出代码

// 购物车storeclass 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();}...

登录后复制

于是,购物车视图就可以自动地刷新了,在官方文档上也有写到。

3.还有一个就是自己粗心造成的。我写完这个项目后,和朋友出去玩时,顺便发给朋友看看,他在删除商品时发现,从上往下删删不了,从下往上删就可以。后来我用模拟器测试也是如此,于是就去看看删除商品的逻辑,发现没有问题,再去看store的数据,发现也是可以同步更新的,只是视图没有更新,很神奇,于是我又在FlatList去找原因,终于,原因找到了,主要是在keyExtractor里面,用index是不可以的,要用name来作为key,因为我删除商品方法其实是根据name来删的,而不是index,所以用index来作为FlatList的Item的key时是会出现bug的。

_keyExtractor = (item,index)=> {  // 千万别用index,不然在删购物车数据时,如果从第一个item开始删会产生节点渲染错乱的bug  return item.name}

登录后复制

相信看了本文案例你已经掌握了方法,更多精彩请关注【创想鸟】其它相关文章!

推荐阅读:

Angular实现可添加删除与计算总金额效果插件

AngularJS实现猜数字小游戏

以上就是React-Native+Mobx实现商城APP的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2772810.html

(0)
上一篇 2025年3月8日 13:32:57
下一篇 2025年2月21日 16:09:38

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • springmvc实现注解拦截器

    这次给大家带来springmvc实现注解拦截器,springmvc实现注解拦截器的注意事项有哪些,下面就是实战案例,一起来看一下。 最近在用SpringMvc写项目的时候,遇到一个问题,就是方法的鉴权问题,这个问题弄了一天了终于解决了,下面…

    编程技术 2025年3月8日
    200
  • JS如何实现Ajax的请求函数

    这次给大家带来JS如何实现Ajax的请求函数,JS实现Ajax请求函数的注意事项有哪些,下面就是实战案例,一起来看一下。 一般我们写网页的时候,如果用到 Ajax 请求服务器,都是使用 JQuery 等已经封装好的库来调用,比较简单。 但是…

    编程技术 2025年3月8日
    200
  • Angular验证功能实现步奏

    这次给大家带来Angular验证功能实现步奏,Angular验证功能实现的注意事项有哪些,下面就是实战案例,一起来看一下。 完整实例代码如下: angular验证功能 input{ display: block; } ul li{ colo…

    编程技术 2025年3月8日
    200
  • element-ui实现导入导出

    这次给大家带来element-ui实现导入导出,element-ui实现导入导出的注意事项有哪些,下面就是实战案例,一起来看一下。 前言 众所周知,ElementUI,是一个比较完善的UI库,但是使用它需要有一点vue的基础。在开始本文的正…

    编程技术 2025年3月8日
    200
  • 一个单独页面内如何实现两个zTree联动

    这次给大家带来一个单独页面内如何实现两个zTree联动,一个单独页面内实现两个zTree联动的注意事项有哪些,下面就是实战案例,一起来看一下。 简介 zTree 是利用 JQuery 的核心代码,实现一套能完成大部分常用功能的 Tree 插…

    编程技术 2025年3月8日
    200
  • easyui的下拉框动态级联加载的实现方法(附代码)

    这次给大家带来easyui的下拉框动态级联加载的实现方法(附代码),easyui下拉框动态级联加载的注意事项有哪些,下面就是实战案例,一起来看一下。 easyui的下拉框动态加载数据,高校中要根据首先查询所有学院,然后根据学院动态加载课程。…

    2025年3月8日
    200
  • 怎样实现组件相互跳转

    这次给大家带来怎样实现组件相互跳转,实现组件相互跳转的注意事项有哪些,下面就是实战案例,一起来看一下。 通过VueRouter来实现组件之间的跳转,供大家参考,具体内容如下 提供了3种方式实现跳转: ①直接修改地址栏中的路由地址 {{msg…

    编程技术 2025年3月8日
    200
  • JSONP的实现原理

    这次给大家带来JSONP的实现原理,使用JSONP的注意事项有哪些,下面就是实战案例,一起来看一下。 JSONP的实现原理 相信很多从事前后端分离的人对于JSONP也是经常接触的,不过很多新手对于JSONP,不知道怎么去实现以及它的实现原理…

    编程技术 2025年3月8日
    200
  • vue组件怎么实现猜数字功能

    这次给大家带来vue组件怎么实现猜数字功能,vue组件实现猜数字功能的注意事项有哪些,下面就是实战案例,一起来看一下。 vue组件猜数字游戏 {{msg}} /* *创建一个组件,my-game: 猜数字大小。 组件:一个input和一个p…

    编程技术 2025年3月8日
    200
  • vue路由嵌套SPA的实现方法

    这次给大家带来vue路由嵌套SPA的实现方法,vue路由嵌套SPA实现的注意事项有哪些,下面就是实战案例,一起来看一下。 本文为大家分享了路由嵌套的SPA实现的步骤: A(/a)组件需要嵌套B组件(/b)和C组件(/c) ①准备嵌套其它组价…

    编程技术 2025年3月8日
    200

发表回复

登录后才能评论