React Native学习之组件通讯三种方案
前文购物车案例:Gouwu组件pop之后,Home组件的已选商品数量如何更新?
前文采用的是 Navigator 传递参数的方式,现做一下总结。
//navigator.push()传递参数
goGouWu() {
const { navigator } = this.props;
//为什么这里可以取得 props.navigator?请看上文:
//<Component {...route.params} navigator={navigator} />
//这里传递了navigator作为props
const _that = this;
if (navigator) {
navigator.push({
name: 'GouWu',
component: GouWu,
params:{
getCount: function(count) {
_that.setState({
count: count,
});
console.log('参数传回');
},
},
})
}
}
//navigator.pop()回传参数
paySuccess() {
var _that = this;
AsyncStorage.clear(function(err){
if (!err) {
_that.setState({
data: [],
price: 0,
});
const { navigator } = _that.props;
if (_that.props.getCount) {
_that.props.getCount(0);
}
alert("支付成功!")
if (navigator) {
navigator.pop();
}
//_that.props.navigator.pop();
}
});
}
方案1:通过组件生命周期中更新阶段的回调函数
更新阶段主要发生在用户操作之后或父组件有更新的时候,此时会根据用户的操作行为进行相应的页面结构的调整。更新阶段可依次执行的回调函数包括:
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
pop之后,数据已经改变了,但是前面的组件没有变化,组件的数据不同步,解决方案:监听didfocus事件,focus到当前路由的时候重新加载数据。
navigationContext.addListener('didfocus', callback)
关键代码:
componentWillMount() {
console.log('List -> componentWillMount');
let navigator = this.props.navigator;
let callback = (event) => {
console.log(
'List : 事件类型',
{
route: JSON.stringify(event.data.route),
target: event.target,
type: event.type,
}
);
};
// Observe focus change events from this component.
this._listeners = [
navigator.navigationContext.addListener('willfocus', callback),
navigator.navigationContext.addListener('didfocus', callback),
];
}
componentWillUnmount() {
console.log('List -> componentWillUnmount');
this._listeners && this._listeners.forEach(listener => listener.remove());
}
更新获取导航路由回传数据不用放到componentDidMount
,直接放到didfocus
的回调即可。
方案2:Navigator参数传递
往下一个路由push的时候传递参数(一个回调),在组件pop之前先调用此回调刷新数据。
关键代码:
goGouWu() {
const { navigator } = this.props;
//为什么这里可以取得 props.navigator?请看上文:
//<Component {...route.params} navigator={navigator} />
//这里传递了navigator作为props
let _that = this;
if (navigator) {
navigator.push({
name: 'GouWu',
component: GouWu,
params: {
fetchData: function () {
console.log('启动fetchData的方法');
AsyncStorage.clear(function (err) {
if (!err) {
_that.setState({
count: 0,
});
alert('购物车已经清空');
}
});
}
}
})
}
}
//在点击清空购物车之后,马上pop,同时触发回调
clearStorage() {
//触发一下回调 让数据同步
console.log('点击清空购物车');
if (this.props.fetchData) {
console.log('回调清空数据');
this.props.fetchData();
}
const { navigator } = this.props;
if (navigator) {
navigator.pop();
}
}
还有一种情况:在点击清空购物车之后,不马上pop,而是通过点击物理back键去触发回调
错误做法:
const top = routers[routers.length - 1];
console.log('栈顶的路由 -> ' + top.component);
if (top.component.props.fetchData) {
console.log('回调fetchData');
top.component.props.fetchData();
}
错误原因:route.component
是一个class
而不是一个object instance
,在里面找props
是不可能找得到的。
如果一定需要从route上找到instance,需要在renderScene里给render的东西指定ref
类似<Component ref = {r => route.ref = r} />
,然后通过route.ref
来访问,但注意不应该假设route.ref
总是有值
一定要判断下 if(route.ref)
方案3:采用redux/event等方式完成跨组件通讯
社区主流还是redux,但是建议大家抛弃redux,因为太繁琐了,我们马上有更方便的架构,来自nodejs社区的,不是前端的方案。
React Native官方并不提供这个方案,redux也不是官方的,涉及到十几个插件,核心是decorator
,都是npm上的插件。主要是一种前端后端的结构和风格一致的思想,Facebook的野心:学习一次,编写任何平台!
React Native支持Web Android iOS Win10 Nodejs跑服务器端
注意:方案1不推荐,推荐方案2或3
源码
方案一完整代码:
/**
* Sample React Native App
* https://github.com/facebook/react-native
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
Navigator,
ScrollView,
Image,
AsyncStorage,
TouchableOpacity,
View,
Platform,
BackAndroid,
ToastAndroid,
} from 'react-native';
import Dimensions from 'Dimensions';
const width = Dimensions.get('window').width;
const height = Dimensions.get('window').height;
const Model = [
{
id: '1',
title: '红心猕猴桃',
desc: '12个装70-90g/个',
price: 49,
url: 'http://note.youdao.com/yws/api/personal/file/62EAF0C6AC8142EA89B11A71BB6C8AEC?method=download&inline=true&shareKey=e6b1c5b1307f752c9e4925056a4facd9',
},
{
id: '2',
title: '红富士苹果',
desc: '5kg果径80-85mm',
price: 109,
url: 'http://note.youdao.com/yws/api/personal/file/E38B11859CB2496190BF5A559D9E68B5?method=download&inline=true&shareKey=1dabf3633a1051e9f5d2d7470fd91c0b',
},
{
id: '3',
title: '哈密瓜',
desc: '2个装1.4kg以上/个',
price: 42,
url: 'http://note.youdao.com/yws/api/personal/file/F443648C199346FDA7E48AE88D0D00A2?method=download&inline=true&shareKey=89fdcc577f98ecdddfcf03f575767381',
},
{
id: '4',
title: '青芒',
desc: '1kg500g以上/个',
price: 28,
url: 'http://note.youdao.com/yws/api/personal/file/8F7B83A47CA94435A2132DC0341AECC3?method=download&inline=true&shareKey=d679e8800b5678f9c673538b93dc0fbc',
},
{
id: '5',
title: '黑珍珠葡萄',
desc: '1kg装',
price: 32,
url: 'http://note.youdao.com/yws/api/personal/file/AF297F8C75714DE481E87C6F09D97649?method=download&inline=true&shareKey=8f89c3673e8851efb20abccce2214fbf',
},
{
id: '6',
title: '红心火龙果',
desc: '2.5kg装250-350g/个',
price: 59.9,
url: 'http://note.youdao.com/yws/api/personal/file/B67D0D453865459594C0FDC6CDE95A79?method=download&inline=true&shareKey=3bc5b3b1ee9f13e3a7ebdd251d117796',
},
];
class RNAPP extends Component {
render() {
let defaultName = 'Home';
let defaultComponent = Home;
return (
<Navigator
initialRoute = {{ name: defaultName, component: defaultComponent }}
ref = "navigator"
//配置场景
configureScene = {
(route) => {
//这个是页面之间跳转时候的动画,具体有哪些?可以看这个目录下,有源代码的: node_modules/react-native/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js
return Navigator.SceneConfigs.VerticalDownSwipeJump;
}
}
renderScene = {
(route, navigator) => {
let Component = route.component;
return <Component {...route.params} navigator={navigator} />
}
}
/>
);
}
componentWillMount() {
if (Platform.OS === 'android') {
BackAndroid.addEventListener('hardwareBackPress', this.onBackAndroid);
//BackAndroid.addEventListener('hardwareBackPress', this.onBackAndroid, true);
}
}
componentWillUnmount() {
if (Platform.OS === 'android') {
BackAndroid.removeEventListener('hardwareBackPress', this.onBackAndroid);
}
}
onBackAndroid = () => {
const navigator = this.refs.navigator;
const routers = navigator.getCurrentRoutes();
console.log('当前路由长度:' + routers.length);
if (routers.length > 1) {
navigator.pop();
return true; //接管默认行为
} else {
if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {
//最近2秒内按过back键,可以退出应用。
return false;
}
this.lastBackPressed = Date.now();
ToastAndroid.show('再按一次退出应用', ToastAndroid.SHORT);
return true;
}
return false; //默认行为
};
}
class Home extends Component {
render() {
return (
<List navigator={this.props.navigator} />
);
}
}
class Item extends Component {
static defaultProps = {
url: '',
title: '默认标题',
};
static propTypes = {
url: React.PropTypes.string.isRequired,
title: React.PropTypes.string.isRequired,
};
render() {
return (
<View style={styles.item}>
<TouchableOpacity onPress={this.props.press}>
<Image
resizeMode='stretch'
style={styles.img}
source={{ uri: this.props.url }}
>
<Text numberOfLines={1} style={styles.item_text}>{this.props.title}</Text>
</Image>
</TouchableOpacity>
</View>
);
}
}
class List extends Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
shouldComponentUpdate() {
console.log('List -> shouldComponentUpdate');
return true;
}
componentWillUpdate() {
console.log('List -> componentWillUpdate');
}
componentDidUpdate() {
console.log('List -> componentDidUpdate');
}
componentWillMount() {
console.log('List -> componentWillMount');
let navigator = this.props.navigator;
let callback = (event) => {
console.log(
'List : 事件类型',
{
route: JSON.stringify(event.data.route),
target: event.target,
type: event.type,
}
);
if ('Home' === event.data.route.name && 'didfocus' === event.type) {
let _that = this;
AsyncStorage.getAllKeys(
function (err, keys) {
if (err) {
//TODO:存储取数据出错
//给用户提示错误信息
console.log(err);
} else {
console.log('读取成功的个数:' + keys.toString());
}
_that.setState({
count: keys.length,
});
}
);
}
};
// Observe focus change events from this component.
this._listeners = [
navigator.navigationContext.addListener('willfocus', callback),
navigator.navigationContext.addListener('didfocus', callback),
];
}
componentWillUnmount() {
console.log('List -> componentWillUnmount');
this._listeners && this._listeners.forEach(listener => listener.remove());
}
render() {
console.log('List -> render');
let list = [];
for (let i in Model) {
if (i % 2 === 0) {
//两个等号:不判断类型
//三个等号:判断类型
let row = (
<View style={styles.row} key={i}>
<Item
title={Model[i].title}
url={Model[i].url}
press={this.press.bind(this, Model[i]) }
>
</Item>
<Item
title={Model[parseInt(i) + 1].title}
url={Model[parseInt(i) + 1].url}
press={this.press.bind(this, Model[parseInt(i) + 1]) }
>
</Item>
</View>
);
list.push(row);
}
}
let count = this.state.count;
let str = null;
if (count) {
str = ', 共' + count + '件商品';
}
console.log('count=' + count);
return (
<ScrollView style={{ marginTop: 10 }}>
{list}
<Text onPress={this.goGouWu.bind(this) } style={styles.btn}>去结算{str}</Text>
</ScrollView>
);
}
goGouWu() {
//alert('点击了去购物车');
const { navigator } = this.props;
//为什么这里可以取得 props.navigator?请看上文:
//<Component {...route.params} navigator={navigator} />
//这里传递了navigator作为props
const _that = this;
if (navigator) {
navigator.push({
name: 'GouWu',
component: GouWu,
})
}
}
press(data) {
this.setState({
count: this.state.count + 1,
});
//AsyncStorage异步存储
AsyncStorage.setItem('SP-' + this.genId() + '-SP', JSON.stringify(data), function (err) {
if (err) {
//TODO:存储出错
alert(err);
} else {
//alert('保存成功');
}
});
}
//生成随机ID:GUID 全局唯一标识符(GUID,Globally Unique Identifier)是一种由算法生成的二进制长度为128位的数字标识符
//GUID生成的代码来自于Stoyan Stefanov
genId() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
let r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
}).toUpperCase();
}
componentDidMount() {
let _that = this;
AsyncStorage.getAllKeys(
function (err, keys) {
if (err) {
//TODO:存储取数据出错
//给用户提示错误信息
console.log(err);
} else {
console.log('读取成功的个数:'+keys.toString());
}
_that.setState({
count: keys.length,
});
}
);
}
}
class GouWu extends Component {
constructor(props) {
super(props);
this.state = {
price: 0,
data: [],
};
}
render() {
//第二次render的时候 data不为空
let data = this.state.data;
let price = this.state.price;
let list = [];
for (let i in data) {
price += parseFloat(data[i].price);
list.push(
<View style={[styles.row, styles.list_item]} key={i}>
<Text style={styles.list_item_desc}>
{data[i].title}
{data[i].desc}
</Text>
<Text style={styles.list_item_price}>人民币: {data[i].price}</Text>
</View>
);
}
let str = null;
if (price) {
str = ', 共' + price.toFixed(2) + '元';
}
return (
<ScrollView style={{ marginTop: 10 }}>
{list}
<Text style={styles.btn} onPress={this.paySuccess.bind(this)} >支付{str}</Text>
<Text style={styles.clear} onPress={this.clearStorage.bind(this) }>清空购物车</Text>
</ScrollView>
);
}
componentDidMount() {
let _that = this;
AsyncStorage.getAllKeys(
function (err, keys) {
if (err) {
//TODO 存储数据出错
return;
}
//keys是字符串数组
AsyncStorage.multiGet(keys, function (err, result) {
//得到的结构是二维数组
//result[i][0]表示我们存储的键,result[i][1]表示我们存储的值
let arr = [];
for (let i in result) {
arr.push(JSON.parse(result[i][1]));
}
_that.setState({
data: arr,
});
});
}
);
}
paySuccess() {
console.log('Gouwu -> 点击支付按钮');
var _that = this;
AsyncStorage.clear(function(err){
if (!err) {
_that.setState({
data: [],
price: 0,
});
const { navigator } = _that.props;
alert("支付成功!")
if (navigator) {
navigator.pop();
}
//_that.props.navigator.pop();
}
});
}
clearStorage() {
let _that = this;
AsyncStorage.clear(function (err) {
if (!err) {
_that.setState({
data: [],
price: 0,
});
alert('购物车已经清空');
}
});
}
}
const styles = StyleSheet.create({
list_item: {
marginLeft: 5,
marginRight: 5,
padding: 5,
borderWidth: 1,
height: 32,
borderRadius: 3,
borderColor: '#ddd',
},
list_item_desc: {
flex: 2,
fontSize: 15,
},
list_item_price: {
flex: 1,
fontSize: 15,
textAlign: 'right',
},
clear: {
marginTop: 10,
backgroundColor: '#FF7200',
color: '#fff',
borderWidth: 1,
borderColor: '#ddd',
marginLeft: 10,
marginRight: 10,
lineHeight: 24,
height: 33,
fontSize: 18,
textAlign: 'center',
textAlignVertical: 'center',
},
btn: {
flex: 1,
backgroundColor: '#FF7200',
height: 33,
textAlign: 'center',
textAlignVertical: 'center',
color: '#fff',
marginLeft: 10,
marginRight: 10,
lineHeight: 24,
marginTop: 40,
fontSize: 18,
},
row: {
flexDirection: 'row',
marginBottom: 10,
},
img: {
flex: 1,
backgroundColor: 'transparent',
},
item_text: {
backgroundColor: '#000',
opacity: 0.7,
color: '#fff',
height: 25,
lineHeight: 18,
textAlign: 'center',
marginTop: 94,
},
item: {
flex: 1,
marginLeft: 5,
borderWidth: 1,
borderColor: '#ddd',
marginRight: 5,
height: 120,
},
list: {
justifyContent: 'flex-start',
flexDirection: 'row',
flexWrap: 'wrap'
},
container: {
flex: 1,
},
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
},
thumbnail: {
width: 80,
height: 80,
borderRadius: 16,
},
//使rightContainer在父容器中占据Image之外剩下的全部空间
container1: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
title: {
fontSize: 14,
marginBottom: 8,
},
year: {
fontSize: 14,
},
});
AppRegistry.registerComponent('RNAPP', () => RNAPP);
Console输出:
List -> shouldComponentUpdate //选中第一件商品
List -> componentWillUpdate
List -> render
count=1
List -> componentDidUpdate
List -> shouldComponentUpdate //选中第二件商品
List -> componentWillUpdate
List -> render
count=2
List -> componentDidUpdate
List : 事件类型 Object {route: "{"name":"GouWu"}", target: NavigationContext, type: "willfocus"} //即将跳转Gouwu页面
List -> shouldComponentUpdate
List -> componentWillUpdate
List -> render
count=2
List -> componentDidUpdate
List : 事件类型 Object {route: "{"name":"GouWu"}", target: NavigationContext, type: "didfocus"} //完成跳转Gouwu页面
Gouwu -> 点击支付按钮
List : 事件类型 Object {route: "{"name":"Home"}", target: NavigationContext, type: "willfocus"} //即将跳回Home页面
List -> shouldComponentUpdate
List -> componentWillUpdate
List -> render
count=2
List -> componentDidUpdate
List : 事件类型 Object {route: "{"name":"Home"}", target: NavigationContext, type: "didfocus"} //完成跳回Home页面
读取成功的个数:
List -> shouldComponentUpdate
List -> componentWillUpdate
List -> render
count=0
List -> componentDidUpdate
方案二完整代码:
/**
* Sample React Native App
* https://github.com/facebook/react-native
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
Navigator,
ScrollView,
Image,
AsyncStorage,
TouchableOpacity,
View,
Platform,
BackAndroid,
ToastAndroid,
} from 'react-native';
import Dimensions from 'Dimensions';
const width = Dimensions.get('window').width;
const height = Dimensions.get('window').height;
const Model = [
{
id: '1',
title: '红心猕猴桃',
desc: '12个装70-90g/个',
price: 49,
url: 'http://note.youdao.com/yws/api/personal/file/62EAF0C6AC8142EA89B11A71BB6C8AEC?method=download&inline=true&shareKey=e6b1c5b1307f752c9e4925056a4facd9',
},
{
id: '2',
title: '红富士苹果',
desc: '5kg果径80-85mm',
price: 109,
url: 'http://note.youdao.com/yws/api/personal/file/E38B11859CB2496190BF5A559D9E68B5?method=download&inline=true&shareKey=1dabf3633a1051e9f5d2d7470fd91c0b',
},
{
id: '3',
title: '哈密瓜',
desc: '2个装1.4kg以上/个',
price: 42,
url: 'http://note.youdao.com/yws/api/personal/file/F443648C199346FDA7E48AE88D0D00A2?method=download&inline=true&shareKey=89fdcc577f98ecdddfcf03f575767381',
},
{
id: '4',
title: '青芒',
desc: '1kg500g以上/个',
price: 28,
url: 'http://note.youdao.com/yws/api/personal/file/8F7B83A47CA94435A2132DC0341AECC3?method=download&inline=true&shareKey=d679e8800b5678f9c673538b93dc0fbc',
},
{
id: '5',
title: '黑珍珠葡萄',
desc: '1kg装',
price: 32,
url: 'http://note.youdao.com/yws/api/personal/file/AF297F8C75714DE481E87C6F09D97649?method=download&inline=true&shareKey=8f89c3673e8851efb20abccce2214fbf',
},
{
id: '6',
title: '红心火龙果',
desc: '2.5kg装250-350g/个',
price: 59.9,
url: 'http://note.youdao.com/yws/api/personal/file/B67D0D453865459594C0FDC6CDE95A79?method=download&inline=true&shareKey=3bc5b3b1ee9f13e3a7ebdd251d117796',
},
];
class RNAPP extends Component {
render() {
let defaultName = 'Home';
let defaultComponent = Home;
return (
<Navigator
initialRoute = {{ name: defaultName, component: defaultComponent }}
ref = "navigator"
//配置场景
configureScene = {
(route) => {
//这个是页面之间跳转时候的动画,具体有哪些?可以看这个目录下,有源代码的: node_modules/react-native/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js
return Navigator.SceneConfigs.VerticalDownSwipeJump;
}
}
renderScene = {
(route, navigator) => {
let Component = route.component;
return <Component {...route.params} navigator={navigator} />
}
}
/>
);
}
componentWillMount() {
if (Platform.OS === 'android') {
BackAndroid.addEventListener('hardwareBackPress', this.onBackAndroid);
//BackAndroid.addEventListener('hardwareBackPress', this.onBackAndroid, true);
}
}
componentWillUnmount() {
if (Platform.OS === 'android') {
BackAndroid.removeEventListener('hardwareBackPress', this.onBackAndroid);
}
}
onBackAndroid = () => {
const navigator = this.refs.navigator;
const routers = navigator.getCurrentRoutes();
console.log('当前路由长度:' + routers.length);
if (routers.length > 1) {
navigator.pop();
return true; //接管默认行为
} else {
if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {
//最近2秒内按过back键,可以退出应用。
return false;
}
this.lastBackPressed = Date.now();
ToastAndroid.show('再按一次退出应用', ToastAndroid.SHORT);
return true;
}
return false; //默认行为
};
}
class Home extends Component {
render() {
return (
<List navigator={this.props.navigator} />
);
}
}
class Item extends Component {
static defaultProps = {
url: '',
title: '默认标题',
};
static propTypes = {
url: React.PropTypes.string.isRequired,
title: React.PropTypes.string.isRequired,
};
render() {
return (
<View style={styles.item}>
<TouchableOpacity onPress={this.props.press}>
<Image
resizeMode='stretch'
style={styles.img}
source={{ uri: this.props.url }}
>
<Text numberOfLines={1} style={styles.item_text}>{this.props.title}</Text>
</Image>
</TouchableOpacity>
</View>
);
}
}
class List extends Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
render() {
let list = [];
for (let i in Model) {
if (i % 2 === 0) {
//两个等号:不判断类型
//三个等号:判断类型
let row = (
<View style={styles.row} key={i}>
<Item
title={Model[i].title}
url={Model[i].url}
press={this.press.bind(this, Model[i]) }
>
</Item>
<Item
title={Model[parseInt(i) + 1].title}
url={Model[parseInt(i) + 1].url}
press={this.press.bind(this, Model[parseInt(i) + 1]) }
>
</Item>
</View>
);
list.push(row);
}
}
let count = this.state.count;
let str = null;
if (count) {
str = ', 共' + count + '件商品';
}
console.log('count=' + count);
return (
<ScrollView style={{ marginTop: 10 }}>
{list}
<Text onPress={this.goGouWu.bind(this) } style={styles.btn}>去结算{str}</Text>
</ScrollView>
);
}
goGouWu() {
//alert('点击了去购物车');
const { navigator } = this.props;
//为什么这里可以取得 props.navigator?请看上文:
//<Component {...route.params} navigator={navigator} />
//这里传递了navigator作为props
let _that = this;
if (navigator) {
navigator.push({
name: 'GouWu',
component: GouWu,
params: {
fetchData: function () {
console.log('启动fetchData的方法');
AsyncStorage.clear(function (err) {
if (!err) {
_that.setState({
count: 0,
});
alert('购物车已经清空');
}
});
}
}
})
}
}
press(data) {
this.setState({
count: this.state.count + 1,
});
//AsyncStorage异步存储
AsyncStorage.setItem('SP-' + this.genId() + '-SP', JSON.stringify(data), function (err) {
if (err) {
//TODO:存储出错
alert(err);
} else {
//alert('保存成功');
}
});
}
//生成随机ID:GUID 全局唯一标识符(GUID,Globally Unique Identifier)是一种由算法生成的二进制长度为128位的数字标识符
//GUID生成的代码来自于Stoyan Stefanov
genId() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
let r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
}).toUpperCase();
}
componentDidMount() {
let _that = this;
AsyncStorage.getAllKeys(
function (err, keys) {
if (err) {
//TODO:存储取数据出错
//给用户提示错误信息
console.log(err);
} else {
console.log('读取成功的个数:'+keys.toString());
}
_that.setState({
count: keys.length,
});
}
);
}
}
class GouWu extends Component {
constructor(props) {
super(props);
this.state = {
price: 0,
data: [],
};
}
render() {
//第二次render的时候 data不为空
let data = this.state.data;
let price = this.state.price;
let list = [];
for (let i in data) {
price += parseFloat(data[i].price);
list.push(
<View style={[styles.row, styles.list_item]} key={i}>
<Text style={styles.list_item_desc}>
{data[i].title}
{data[i].desc}
</Text>
<Text style={styles.list_item_price}>人民币: {data[i].price}</Text>
</View>
);
}
let str = null;
if (price) {
str = ', 共' + price.toFixed(2) + '元';
}
return (
<ScrollView style={{ marginTop: 10 }}>
{list}
<Text style={styles.btn} onPress={this.paySuccess.bind(this)} >支付{str}</Text>
<Text style={styles.clear} onPress={this.clearStorage.bind(this) }>清空购物车</Text>
</ScrollView>
);
}
componentDidMount() {
let _that = this;
AsyncStorage.getAllKeys(
function (err, keys) {
if (err) {
//TODO 存储数据出错
return;
}
//keys是字符串数组
AsyncStorage.multiGet(keys, function (err, result) {
//得到的结构是二维数组
//result[i][0]表示我们存储的键,result[i][1]表示我们存储的值
let arr = [];
for (let i in result) {
arr.push(JSON.parse(result[i][1]));
}
_that.setState({
data: arr,
});
});
}
);
}
paySuccess() {
var _that = this;
AsyncStorage.clear(function(err){
if (!err) {
_that.setState({
data: [],
price: 0,
});
//触发一下回调,让数据同步
console.log('点击清空购物车');
if (_that.props.fetchData) {
console.log('回调清空数据');
_that.props.fetchData();
}
alert("支付成功!")
const { navigator } = _that.props;
if (navigator) {
navigator.pop();
}
//_that.props.navigator.pop();
}
});
}
clearStorage() {
let _that = this;
AsyncStorage.clear(function (err) {
if (!err) {
_that.setState({
data: [],
price: 0,
});
alert('购物车已经清空');
}
});
}
}
const styles = StyleSheet.create({
list_item: {
marginLeft: 5,
marginRight: 5,
padding: 5,
borderWidth: 1,
height: 32,
borderRadius: 3,
borderColor: '#ddd',
},
list_item_desc: {
flex: 2,
fontSize: 15,
},
list_item_price: {
flex: 1,
fontSize: 15,
textAlign: 'right',
},
clear: {
marginTop: 10,
backgroundColor: '#FF7200',
color: '#fff',
borderWidth: 1,
borderColor: '#ddd',
marginLeft: 10,
marginRight: 10,
lineHeight: 24,
height: 33,
fontSize: 18,
textAlign: 'center',
textAlignVertical: 'center',
},
btn: {
flex: 1,
backgroundColor: '#FF7200',
height: 33,
textAlign: 'center',
textAlignVertical: 'center',
color: '#fff',
marginLeft: 10,
marginRight: 10,
lineHeight: 24,
marginTop: 40,
fontSize: 18,
},
row: {
flexDirection: 'row',
marginBottom: 10,
},
img: {
flex: 1,
backgroundColor: 'transparent',
},
item_text: {
backgroundColor: '#000',
opacity: 0.7,
color: '#fff',
height: 25,
lineHeight: 18,
textAlign: 'center',
marginTop: 94,
},
item: {
flex: 1,
marginLeft: 5,
borderWidth: 1,
borderColor: '#ddd',
marginRight: 5,
height: 120,
},
list: {
justifyContent: 'flex-start',
flexDirection: 'row',
flexWrap: 'wrap'
},
container: {
flex: 1,
},
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
},
thumbnail: {
width: 80,
height: 80,
borderRadius: 16,
},
//使rightContainer在父容器中占据Image之外剩下的全部空间
container1: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
title: {
fontSize: 14,
marginBottom: 8,
},
year: {
fontSize: 14,
},
});
AppRegistry.registerComponent('RNAPP', () => RNAPP);
版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/02/25/react-native-learning-for-three-component-communication-schemes/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论