Home > Web Front-end > JS Tutorial > body text

React-Native+Mobx implements mall APP

php中世界最好的语言
Release: 2018-04-13 15:04:25
Original
3071 people have browsed it

This time I will bring you React-Native Mobx to implement the mall APP. What are the precautions for implementing the mall APP with React-Native Mobx. The following is a practical case, let’s take a look.

I have been learning WeChat mini programs recently. During the learning process, I saw wxapp-mall I thought this WeChat applet project was very good, and the UI was quite small and fresh, so I cloned it to study it. While looking at the source code, I found that it was not complicated. I was really surprised to realize rich functions with not much code. So, I thought, would it be difficult to use react-native to make a small project like this? What's more, writing a set of code can run Android and iOS at the same time (the same goes for small programs...), how about writing one? Come and have fun? With this idea in mind, I directly Let’s write a react-native init project (๑•̀ㅂ•́)و✧

Technical framework and components

  • 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"

Why use Mobx?

Mobx is a scalable state management tool that is simpler than react-redux and faster to get started. In this small project, because there is no background service interface, all local fake data is used. In order to simulate the implementation Browse products =>Add to shopping cart=>Checkout=>Clear shopping cart=>Restore products to their original state In such a process, Mobx is used to manage all data and product status (whether it is selected, whether it is added to the shopping cart), so that all pages can share data and change the status of the product, and the data and products between pages can be shared. The status is updated synchronously. Specifically, how to use Mobx to implement this process, I will share my experience of using it and some pitfalls encountered below.

start

First react-native Init a project, and then use yarn or npm to install all dependencies and components. Because using Mobx will use the decorator in ES7, you need to install it babel-plugin-transform-decorators-legacy plug-in, and then add some content under the .babelrc file.

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

Project Structure

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

In the Root.js file, regarding the configuration and usage of react-navigation, you can refer to the official documentation and this blog, which are written in great detail. I have found answers to questions about react-navigation in these two articles. The relevant react-navigation configuration, usage methods and project page layout and component writing are not going to be elaborated here because they are relatively simple. They are more about discussing some logic and methods of Mobx implementation functions. , The components under the screen folder are all commented (°ー°〃)

Let’s mainly talk about Mobx

1. Data storage and retrieval

These are simulated and implemented using fake data. At the very beginning, write the data structure of the fake data, for example:

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

store.js in the Mobx folder, here it mainly stores and manages the data of all products used by the app, and moves the logic and state from the component to an independent, testable unit. This unit is on each page. You can use it

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()
Copy after login

RootStore is used here to instantiate all stores (shopping cart, homepage, and category pages have their own stores),

In this way, stores can be managed and operated through RootStore, allowing them to communicate with each other and share references.

Secondly, the @observable method of Mobx is used to store data, which turns the data into an observer. When the user operates the view and causes the data to change, the view can be automatically updated with the @observer provided by react-mobx, which is very convenient.

In addition, in order to inject Mobx's Rootstore into react-native components, it must be implemented through the Provider provided by mobx-react. Under Root.js, I wrote this:

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

After injecting the Rootstore instance into the component tree, can it be obtained directly by using this.props.rootStore in the component?

‘'不是的”,我们还需要在要用到Rootstore的组件里,要加点小玩意,在 HomeScreen.js (首页)中这么写:

import { inject, observer } from 'mobx-react'
@inject('rootStore') // 缓存rootStore,也就是在Root.js注入的
@observerexport default class HomeScreen extends Component {
 ......
}
Copy after login

加上了 @inject('rootStore') ,我们就可以愉快地使用 this.props.rootStore 来拿到我们想要的数据啦^_^ ,同样,在商品信息,分类页,购物车页面js下,也需要使用 @inject('rootStore') 来实现数据的获取,然后再一步步地把数据传到它们的子组件中。

2. 加入购物车的实现

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

React-Native+Mobx implements mall 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 
 }}
Copy after login

简单的说,先获取水果的名称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
}}
Copy after login

所有修改商品状态的逻辑都在上面代码里面,其中,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)}
Copy after login

这里主要用了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>
Copy after login

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

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

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

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

推荐阅读:

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

AngularJS实现猜数字小游戏

The above is the detailed content of React-Native+Mobx implements mall APP. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template