php react-native,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实例,首页新品,分类页,商品详情页,购物车页面都要用到store

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

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

be6b32f1f1.gif

实现方法 :

在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 <=0 )

return

this.allDatas.totalMoney -= money

}

// 全选

@action

allSelect() {

if(this.allDatas.isAllSelected) {

// 重置totalMoney

this.allDatas.totalMoney = 0

this.allDatas.data.forEach(e=> {

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

}

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/525852.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql 流程控制语句,mysql PL(procedure language)流程控制语句

在MySQL中&#xff0c;常见的过程式SQL语句可以用在存储体中。其中包括IF语句、CASE语句、LOOP语句、WHILE语句、ITERATE语句和LEAVE语句&#xff0c;它们可以进行流程控制。IF语句相当于Java中的if()...else if()...else...CASE语句相当于Java中的switch()...case A:...break;…

mysql 空闲几分钟速度变慢,MYSQL 运作一小段时间后,速度变得奇慢。而CPU基本空闲状态...

当前位置:我的异常网 MySQL MYSQL 运作一小段时间后&#xff0c;速度变得奇慢。而CPU基本MYSQL 运作一小段时间后&#xff0c;速度变得奇慢。而CPU基本空闲状态www.myexceptions.net 网友分享于&#xff1a;2015-08-26 浏览&#xff1a;11次MYSQL 运行一小段时间后&#xff…

matlab axis 用法,MATLAB中regionprops的用法

Matlab图像处理函数&#xff1a;regionprops这里给出在Matlab图像处理工具箱中非常重要的一个图像分析函数&#xff1a;regionprops。顾名思义&#xff1a;它的用途是get the properties of region&#xff0c;即用来度量图像区域属性的函数。语法STATS regionprops(L,propert…

emqx配置mysql认证,emqx使用mysql完成用户密码验证和ACL鉴权

emqx使用mysql完成用户密码验证和ACL鉴权emqx使用mysql完成用户密码验证和ACL鉴权摘要&#xff1a;前几篇博客介绍的是使用配置文件配置了ACL和客户端用户名密码配置实现生产环境下的安全登录和权限控制&#xff0c;各项配置比较繁琐&#xff0c;修改起来比较麻烦&#xff0c;下…

MATLAB课程表分配问题,求助matlab大神,学校的课程安排太骚了,我们压根就不用学matlab...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼上了MATLAB&#xff0c;可是对数学完全不感兴趣。老师弄了个作业&#xff0c;代码附件了。求大佬帮忙理解原理后简单做一个不一样的过程的程序。帮忙注释一下代码。(一开始忘记下载要币了。不好意思)两个.m文件&#xff0c;需要放一…

php时间转分钟前,PHP把时间转换成几分钟前几小时前几天前

现在很多网站将时间的显示都变得比较人性化&#xff0c;今天项目有一个也需要在对应的资讯后面显示为几分钟前、几小时前&#xff0c;接下来吾爱编程为大家分享一下PHP把时间转换成几分钟前、几小时前几天前的方法&#xff0c;有需要的小伙伴可以参考一下&#xff1a;1、项目需…

emlog_toolkit.php,emlog 4.0版本IIS6下伪静态划定规矩

emlog默许不能生成静态文件&#xff0c;不过彷佛有生成静态页面的相干插件&#xff0c;该插件博客吧先不研讨&#xff0c;本日博客簿要引见的是emlog 4.0版本在IIS6环境下的伪静态划定规矩&#xff0c;人人都晓得&#xff0c;经由过程伪静态能够让博客文章网址变得对搜索引擎越…

php如何封装数组,PHP数组转对象 对象转数组封装类

代码如下/*** 数组 转 对象** param array $arr 数组* return object*/function array_to_object($arr) {if (gettype($arr) ! array) {return;}foreach ($arr as $k > $v) {if (gettype($v) array || getType($v) object) {$arr[$k] (object)array_to_object($v);}}retu…

api.php phpcms,phpcms程序api怎么写接口

易站通&#xff0c;带你玩转PHPCMS建站程序&#xff0c;让你更快的熟悉该程序下面让我们来学习吧phpcms api怎么写接口&#xff1f;最近自己开发了一套crm系统&#xff0c;想着如果将来能卖出去&#xff0c;能不能再界面动态调用自己网站的推荐信息&#xff0c;算是一种广告吧&…

oracle修改窗口字体大小,jQuery之字体大小的设置方法

先获取字体大小&#xff0c;进行处理。再将修改的值保存。slice() 方法可从已有的数组中返回选定的元素。arrayObject.slice(start,end)。start 必需。规定从何处开始选取。如果是负数&#xff0c;那么它规定从数组尾部开始算起的位置。也就是说&#xff0c;-1 指最后一个元素&…

oracle 删除表 索引也会删除吗,Oracle 删除当前用户下所有的表、索引、序列

通过下面语句可以得到要删除Oracle的所有表、索引、序列... 的语句select drop table || table_name ||;||chr(13)||chr(10) from user_tables; --delete tablesselect drop view || view_name||;||chr(13)||chr(10) from user_views; --delete viewsselect drop sequence …

基于Java、Kafka、ElasticSearch的搜索框架的设计与实现

Jkes是一个基于Java、Kafka、ElasticSearch的搜索框架。Jkes提供了注解驱动的JPA风格的对象/文档映射&#xff0c;使用rest api用于文档搜索。项目主页&#xff1a;https://github.com/chaokunyang/jkes安装可以参考jkes-integration-test项目快速掌握jkes框架的使用方法。jkes…

Docker是传统的应用发布管理的终结者么?

译者注&#xff1a;使用Docker能真正改善传统的应用发布管理中遇到的问题么&#xff1f;以下是译文&#xff1a;自从2013年发布以来&#xff0c;Docker已经成为每一个操作管理者眼中的最爱。如果你一直与世隔绝&#xff0c;这里恰恰是你错过的部分。Docker是在一个操作环境地址…

基于Mesos/Docker构建数据处理平台

本文深入介绍了去哪儿网利用Mesos和Docker构建私有云服务的全过程&#xff0c;分享了从无状态应用向有状态应用逐步过度的经验与心得。平台概览2014年下半年左右&#xff0c;去哪儿完成了有关构建私有云服务的技术调研&#xff0c;并最终拍定了Docker/Mesos这一方案。下图1展示…

Mesos容器引擎的架构设计和实现解析

引言&#xff1a;提到容器&#xff0c;大家第一时间都会想到Docker&#xff0c;毕竟Docker是目前最为流行的容器开源项目&#xff0c;它实现了一个容器引擎&#xff08;Docker engine&#xff09;&#xff0c;并且为容器的创建和管理、容器镜像的生成、分发和下载提供一套非常便…

阿里的盔甲、未来20年发展的动力以及对未来的洞察

刚刚变身迈克尔杰克逊&#xff0c;用“经济体”、“理想主义”等词刷屏的马云又在教师节那天&#xff0c;赶到2017世界物联网博览会&#xff0c;为阿里的物联网站台。过去18年以来&#xff0c;淘宝网、天猫、聚划算、全球速卖通、阿里巴巴国际交易市场、1688、阿里妈妈、蚂蚁金…

MySQL InnoDB Memcached Plugin在Oray公司的实践

1、应用背景介绍我所在职的Oray是一家提供各种互联网服务且具有海量用户的企业&#xff0c;我们也一直在实践各种新技术新架构&#xff1b;缓存方面&#xff0c;我们从memcached、ttserver、redis等都有较多应用&#xff0c;其中redis在我们的dns体系中有着很深度的集成使用&am…

联想超融合平台oracle,联想AIO超融合云一体机解决方案.pdf

联想超融合云一体机解决方案--THINKCLOUD AIO联想云服务集团资深产品经理 赵舜尧2015年6月 zhaosy42015 LENOVO RESTRICTED. All rights reserved.1产品篇2客户收益篇 联想 技术篇THINKCLOUD AIO4测试篇32015 LENOVO RESTRICTED. ALL RIGHTS RESERVED.联想超融合云一体机解决方…

网易数据运河系统NDC设计与应用

【导语】 NDC是网易近一年新诞生的结构化数据传输服务&#xff0c;它整合了网易过去在数据传输领域的各种工具和经验&#xff0c;将单机数据库、分布式数据库、OLAP系统以及下游应用通过数据链路串在一起。除了保障高效的数据传输外&#xff0c;NDC的设计遵循了单元化和平台化的…

oracle数据库pfile文件,Oracle pfile/spfile参数文件详解

Oracle pfile/spfile参数文件详解在创建数据库时&#xff0c;SPFile文件中部分必须考虑的参数值&#xff1a;基本规则a.在SPFile文件中&#xff0c;所有参数都是可选的&#xff0c;也就是说只需要在初始化参数文件中列出那些需要修改的参数&#xff0c;其它保持默认值即可。b.S…