3.1 创建新的电商App之前创建了一个简单的电商项目,本节来实现对该项目的重构。3.1.1 移植旧电商项目(1)先创建React Native项目并安装依赖包。
react-native init ch04 // 新建React Native项目ch04cd ch04npm install // 或者使用cnpm安装:cnpm install?小知识:npm install命令还可以简写成npm i,更多说明可以使用npm help install查看帮助文档。(2)将第2章ch03项目中的index.ios.js、index.android.js以及app.js文件都复制到ch04文件夹中。完成文件复制和覆盖之后,ch04项目的结构如图3.1所示。但是,如果这时候直接运行App,会发生应用ch04没有注册的错误,如图3.2所示。发生错误的AppRegistry.registerComponent函数在第1章的例子中就遇到过,那么它到底有什么作用呢?
图3.1 ch04项目的结构 图3.2 应用ch04没有注册的错误原来,AppRegistry是所有React Native应用的入口,应用的根组件通过AppRegistry. registerComponent方法注册自己,然后原生系统才可以加载React Native应用的代码并运行React Native应用。流程如图3.3所示。
图3.3 AppRegistry.registerComponent注册React Native应用的根组件(3)了解AppRegistry的原理之后,就可以轻松地找到错误的原因,index.ios.js和index.android.js文件中注册的应用名称不正确,React Native应用中注册的应用是ch03,而react-native命令行工具生成的原生代码运行的应用是ch04,产生错误的代码如下:
// index.ios.js和index.android.js文件AppRegistry.registerComponent('ch03', () => app); // React Native注册ch03
// iOS原生项目中的AppDelegate.m文件RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"ch04" // 原生代码运行ch04 initialProperties:nil launchOptions:launchOptions];// Android原生项目中的MainActivity.java文件@Overrideprotected String getMainComponentName() {
return "ch04"; // 原生代码运行ch04}
?提示:这里是我们第一次接触到React Native开发中的原生代码,通常情况下不需要修改原生代码,只要简单了解即可。(4)将React Native代码中注册的应用名称ch03修改为ch04即可,修改index.ios.js和index.android.js代码如下:
01 AppRegistry.registerComponent('ch04', () => app);?提示:由于iOS App和Android App的入口文件不同,分别为index.ios.js和index.android.js,所以ch04项目中的这两个文件都需要按照上述代码进行修改。重新加载应用,效果如图3.4所示。
图3.4 注册正确的应用名称后的运行效果3.1.2 重构现有的代码在成功移植ch03项目的实现到新建的ch04项目后,我们就可以开动了:完善应用。但是,笔者在实际开发过程中总结的经验是,完善的第一步往往是从梳理和重构现有代码开始,而非立即添加新代码或功能。只有不断地重构然后添加新功能,代码的可维护性才会越好,这也是应用稳定性和扩展性的重要保证。重新审视app.js文件的代码,从中不难发现这样的问题:ScrollView组件下所有子组件的样式都是类似的,导致很多冗余代码。ScrollView组件现有代码如下:
01 export default class app extends Component {02 // 这里省略了没有修改的代码03 04 render() {05 return (06 07 // 这里省略了没有修改的代码08 09 10 horizontal={true} 11 showsHorizontalScrollIndicator={false} 12 pagingEnabled={true}>13 Alert.alert
('你单击了轮播图', null, null)}>14 15 width: Dimensions.get('window').width,16 height: 180,17 backgroundColor: 'gray'18 }}>广告119 20 Alert.alert
('你单击了轮播图', null, null)}>21 22 width: Dimensions.get('window').width,23 height: 180,24 backgroundColor: 'orange'25 }}>广告226 27 Alert.alert
('你单击了轮播图', null, null)}>28 29 width: Dimensions.get('window').width,30 height: 180,31 backgroundColor: 'yellow'32 }}>广告333 34 35 36 // 这里省略了没有修改的代码37 38 );39 }40 41 // 这里省略了没有修改的代码42 }
如果想更新轮播广告的高度的话,就需要修改多处代码heigh: 180。因此,可以尝试将重复的样式代码抽离出来,代码效果如下:
01 export default class app extends Component {02 // 这里省略了没有修改的代码03 04 render() {05 return (06 07 // 这里省略了没有修改的代码08 09 10 horizontal={true} 11 showsHorizontalScrollIndicator={false}12 pagingEnabled={true}>13 Alert.alert
('你单击了轮播图', null, null)}>14 15 styles.advertisementContent, {16 backgroundColor: 'gray'17 }18 ]}>广告119 20 Alert.alert
('你单击了轮播图', null, null)}>21 22 styles.advertisementContent, {23 backgroundColor: 'orange'24 }25 ]}>广告226 27 Alert.alert
('你单击了轮播图', null, null)}>28 29 styles.advertisementContent, {30 backgroundColor: 'yellow'31 }32 ]}>广告333 34 35 36 // 这里省略了没有修改的代码37 38 );39 }40 41 // 这里省略了没有修改的代码40 }
其中,添加的样式advertisementContent定义如下:
01 const styles = StyleSheet.create({02 // 这里省略了没有修改的代码03 advertisementContent: {04 width: Dimensions.get('window').width,05 height: 18006 },07 // 这里省略了没有修改的代码08 });
这样,当要修改轮播广告页面的高度时,只需要修改样式advertisementContent这一处,所有广告页面的样式都可以同时更新。虽然,样式代码做到了复用,但是TouchableHighlight组件和单击事件等还是重复的,对此,可以使用JavaScript数组的map()方法来做进一步优化,修改app.js代码如下:
01 export default class app extends Component {02 constructor(props) {03 super(props);04 this.state = {05 advertisements: [ // 轮播广告数组06 { // 数组中的每个成员描述了广告的详细信息07 title: '广告1',08 backgroundColor: 'gray'09 }, {10 title: '广告2',11 backgroundColor: 'orange'12 }, {13 title: '广告3',14 backgroundColor: 'yellow'15 }16 ],17 };18 }19 20 // 这里省略了没有修改的代码21 22 render() {23 return (24 25 // 这里省略了没有修改的代码26 27 28 horizontal={true}29 showsHorizontalScrollIndicator={false}30 pagingEnabled={true}>31 {this.state.advertisements.map((advertisement,
index) => {32 return (33
{() => Alert.alert('你单击了轮播图', null, null)}>34 35 styles.advertisementContent, {36 backgroundColor: advertisement.
backgroundColor37 }38 ]}>{advertisement.title}39
40 ); 41 })} 42 43 44 // 这里省略了没有修改的代码 45 46 ); 47 } 48 49 // 这里省略了没有修改的代码 50 }此时,如果想要修改、添加或删除广告页,对于重构后的代码就非常简单,只需要编辑this.state.advertisements数组即可。重新加载应用,效果如图3.5所示。