From e2673b7557b7c879c83b90c321b47f86a815da73 Mon Sep 17 00:00:00 2001 From: Gemmily Date: Wed, 14 Sep 2016 09:48:56 +0800 Subject: [PATCH 1/2] update update --- .../Readme.md" | 321 +++++++++++++++++- 1 file changed, 320 insertions(+), 1 deletion(-) diff --git "a/React Native \346\257\217\346\227\245\344\270\200\345\255\246/Readme.md" "b/React Native \346\257\217\346\227\245\344\270\200\345\255\246/Readme.md" index 64e774c..fa0f040 100644 --- "a/React Native \346\257\217\346\227\245\344\270\200\345\255\246/Readme.md" +++ "b/React Native \346\257\217\346\227\245\344\270\200\345\255\246/Readme.md" @@ -15,6 +15,16 @@ 7. [D7:解构赋值(Destructuring assignment)(2016-8-26)](#d7解构赋值destructuring-assignment2016-8-26) 8. [D8:React-Native 原生模块调用(iOS) (2016-8-29)](#d8react-native-原生模块调用ios-2016-8-29) 9. [D9:动态属性名&字符串模板(2016-8-30)](#d9动态属性名字符串模板2016-8-30) +10. [D10:优化切换动画卡顿的问题(2016-8-31)](#d10优化切换动画卡顿的问题2016-8-31) +11. [D11:AsyncStorage存储key管理小技巧(2016-9-1)](#d11asyncstorage存储key管理小技巧---) +12. [D12:延展操作符(Spread operator)(2016-9-2)](#d12延展操作符spread-operator2016-9-2) +13. [D13:React Native学习资料整理(2016-9-5)](#d13react-native学习资料整理2016-9-5) +14. [D14:React Native Android跳入RN界面(2016-9-7)](#d14react-native-android跳入rn界面2016-9-7) +15. [D15:为Promise插上可取消的翅膀(2016-9-8)](#d15为promise插上可取消的翅膀2016-9-8) +16. [D16:Image组件遇到的宽高问题(2016-9-9)](#d16image组件遇到的宽高问题2016-9-9) +17. [D17:数据类型优化(2016-9-12)](#d17数据类型优化2016-9-12) +18. [D18:ReactMethod的参数类型(2016-9-14)](#d18reactmethod的参数类型2016-9-14) +19. [D19:ListView滚动平滑(2016-9-14)](#d19listview滚动平滑2016-9-14) ``` 模板: D1:标题 (日期) @@ -26,7 +36,315 @@ D1:标题 (日期) 内容 另外:记得在列表中添加链接 ``` +D19:ListView滚动平滑(2016-9-14) +------ +ListView设计的时候,当需要动态加载非常大的数据的时候,下面的方法性能优化的方法可以让我们的ListView滚动的时候更加平滑: + +- 只更新渲染数据变化的那一行 ,`rowHasChanged`方法会告诉ListView组件是否需要重新渲染当前那一行。 +- 选择渲染的频率 ,默认情况下面每一个`event-loop`(事件循环)只会渲染一行(可以同pageSize自定义属性设置)。这样可以把大的工作量进行分隔,提供整体渲染的性能。 +D18:ReactMethod的参数类型(2016-9-14) +------ +`@ReactMethod`方法中传的参数必须是JavaScript和Java相互对应的。 +```javascript +Boolean -> Bool +Integer -> Number +Double -> Number +Float -> Number +String -> String +Callback -> function +ReadableMap -> Object +ReadableArray -> Array +``` +D17:数据类型优化(2016-9-12) +------ +经常会遇到页面需要加载和渲染数据,有时刷新数据是state中的值没有修改,但是遇到this.setState(),界面就会被重新渲染,因为react-native的生命周期就是,当你调用setState时,总是会触发render的方法。 +###优化1 +可以使用shouldComponentUpdate生命周期方法,此方法作用是在props或 者state改变且接收到新的值时,则在要render方法之前调用。此方法在初始化渲染的时候不会调用,在使用forceUpdate方法的时候也不会。所以在这个方法中我们可以增加些判断规则来避免当state或者props没有改变时所造成的重新render. + +``` +shouldComponentUpdate(dataProps,dataState) { + return dataProps.value !== this.props.value; +} +``` + +###优化2 +如果是一个列表的话这样判断就有问题,这里即使使用了shouldComponentUpdate中的判断,但却一直返回true,导致还会执行render。所以必须对对象所有的键值进行进行比较才能确认是否相等。这里推荐使用facebook自家的immutablejs。一个不可变数据类型的库。使用后可以直接使用以下的写法达到我们之前的目的。immutablejs其他的具体用法请见:[Immutable 详解及 React 中实践](http://www.w3ctech.com/topic/1595)优化后代码如下: + +``` +export default class KSD extends Component { + constructor(props) { + super(props); + this.state = { + data: Immutable.formJS({ + value:{ + value1:'value1', + value2:'value2', + value3:'value3' + } + }) + } + } + shouldComponentUpdate(dataProps,dataState) { + return( + return dataProps.data !== this.props.data; + ) + } +} +``` + +D16:Image组件遇到的宽高问题(2016-9-9) +------ +开发中使用Image组件展示图片,在某些机型上有时并不能得到正确的宽高,设置`resizeMode`无效,此时可以设置宽高属性为`null`这样就可以正常显示了。 + +| 宽度不正确 | 宽度正确 | +|--------------------------------|------------------------------| +|![宽度不正确](./images/D16/1.png) | ![宽度正确](./images/D16/2.png)| + +更多相关问题[Stack Overflow][1] [Github][2] + + +D15:为Promise插上可取消的翅膀(2016-9-8) +------ +`Promise`是React Native开发过程中用于异步操作的最常用的API,但Promise没有提供用于取消异步操作的方法。为了实现可取消的异步操作,我们可以为Promise包裹一层可取消的外衣。 + +```javascript +const makeCancelable = (promise) => { + let hasCanceled_ = false; + const wrappedPromise = new Promise((resolve, reject) => { + promise.then((val) => + hasCanceled_ ? reject({isCanceled: true}) : resolve(val) + ); + promise.catch((error) => + hasCanceled_ ? reject({isCanceled: true}) : reject(error) + ); + }); + return { + promise: wrappedPromise, + cancel() { + hasCanceled_ = true; + }, + }; +}; +``` + +然后可以这样使用取消操作: + +```javascript +const somePromise = new Promise(r => setTimeout(r, 1000));//创建一个异步操作 +const cancelable = makeCancelable(somePromise);//为异步操作添加可取消的功能 +cancelable + .promise + .then(() => console.log('resolved')) + .catch(({isCanceled, ...error}) => console.log('isCanceled', isCanceled)); +// 取消异步操作 +cancelable.cancel(); +``` + +**了解更多:[React Native 性能优化之可取消的异步操作](https://github.com/crazycodeboy/RNStudyNotes/tree/master/React%20Native%20%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/React%20Native%20%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E4%B9%8B%E5%8F%AF%E5%8F%96%E6%B6%88%E7%9A%84%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C)** + + +D14:React Native Android跳入RN界面(2016-9-7) +------ +步骤: +1.新建一个类继承`Activity`,并实现`DefaultHardwareBackBtnHandler`接口 +2.new一个`ReactRootView`,并build 一个`ReactInstanceManager` +3.`setContentView(mReactRootView);` +```java + mReactRootView = new ReactRootView(this); + mReactInstanceManager = ReactInstanceManager.builder() + .setApplication(getApplication()) + .setBundleAssetName("index.android.bundle") + .setJSMainModuleName("index.android") + .addPackage(new MainReactPackage()) + .setUseDeveloperSupport(true) + .setInitialLifecycleState(LifecycleState.RESUMED) + .build(); + Bundle bundle = new Bundle(); + bundle.putString("enter","KsudiReward"); + mReactRootView.startReactApplication(mReactInstanceManager, "KsudiCircle", bundle); + + setContentView(mReactRootView); +``` +其中`KsudiCircle`是RN入口 注册的组件名称,bundle为原生带入RN的属性值 + +D13:React Native学习资料整理(2016-9-5) +------ +收集整理了一些学习指南,包含 教程、开源app和资源网站等的链接,如果需要查阅资料或找寻第三方库,大家可以去查找 + +###资源整合 + +[RNStudyNotes + ★320 ](https://github.com/crazycodeboy/RNStudyNotes)作者的学习笔记,欢迎star,每天不定时更新 + +[awesome-react-native + ★7037](https://github.com/jondot/awesome-react-native) Awesome React Native系列,有最全的第三方组件(推荐!) + +[react-native-guide + ★5777](https://github.com/reactnativecn/react-native-guide) React-Native学习指南,开源App和组件 + + [React Native 高质量学习资料汇总](http://www.jianshu.com/p/454f2e6f28e9) @author ASCE1885整理 + + [React Native 从入门到原理](http://www.jianshu.com/p/978c4bd3a759) 作者@bestswifter + + [深入浅出ES6](www.infoq.com/cn/es6-in-depth/)深入浅出ES6专栏合集迷你书 + +D12:延展操作符(Spread operator)(2016-9-2) +------ +通常我们在封装一个组件时,会对外公开一些 props 用于实现功能。大部分情况下在外部使用都应显示的传递 props 。但是当传递大量的props时,会非常繁琐,这时我们可以使用 `...(延展操作符,用于取出参数对象的所有可遍历属性)` 来进行传递。 + +### 一般情况下我们应该这样写 +``` + +``` + +### 使用 ... ,等同于上面的写法 + +``` +var params = { + + type: 'normal', + + number: 2 + + } + + +``` + +### 配合解构赋值避免传入一些不需要的参数 + +``` +var params = { + name: '123', + title: '456', + type: 'aaa' +} + +var { type, ...other } = params; + + +//等同于 + +``` + + +D11:AsyncStorage存储key管理小技巧 +------ + +### 场景 + +AsyncStorage是React Native推荐的数据存储方式。当我们需要根据条件从本地查询出多条记录时,你会想到来一个`select * from xx where xx`。但是很不幸的告诉你,AsyncStorage +是不支持sql的,因为AsyncStorage是Key-Value存储系统。 + +**那么如何才能快速的从众多记录中将符合条件的记录查询出来呢?** +请往下看... + +### AsyncStorage key管理 + +为了方便查询多条符合规则的记录,我们可以在保存数据前,对这条数据进行分类,然后记录下这条记录的key。下次再查询该数据前,只需要先查询之前保存的key,然后通过 +`static multiGet(keys, callback?) `API,将符合规则的数据一并查询出来。 +### 用例 + +>保存数据 + +**第一步:保存数据** + +```javascript + saveFavoriteItem(key,vaule,callback) { + AsyncStorage.setItem(key,vaule,(error,result)=>{ + if (!error) {//更新Favorite的key + this.updateFavoriteKeys(key,true); + } + }); + } +``` + +**第二步:更新key** + +```javascript +/** + * 更新Favorite key集合 + * @param isAdd true 添加,false 删除 + * **/ + updateFavoriteKeys(key,isAdd){ + AsyncStorage.getItem(this.favoriteKey,(error,result)=>{ + if (!error) { + var favoriteKeys=[]; + if (result) { + favoriteKeys=JSON.parse(result); + } + var index=favoriteKeys.indexOf(key); + if(isAdd){ + if (index===-1)favoriteKeys.push(key); + }else { + if (index!==-1)favoriteKeys.splice(index, 1); + } + AsyncStorage.setItem(this.favoriteKey,JSON.stringify(favoriteKeys)); + } + }); + } +``` + +>查询批量数据 + +**第一步:查询key** + +```javascript +getFavoriteKeys(){//获取收藏的Respository对应的key + return new Promise((resolve,reject)=>{ + AsyncStorage.getItem(this.favoriteKey,(error,result)=>{ + if (!error) { + try { + resolve(JSON.parse(result)); + } catch (e) { + reject(error); + } + }else { + reject(error); + } + }); + }); + } +``` + +**第二步:根据key查询数据** + +```javascript +AsyncStorage.multiGet(keys, (err, stores) => { + try { + stores.map((result, i, store) => { + // get at each store's key/value so you can work with it + let key = store[i][0]; + let value = store[i][1]; + if (value)items.push(JSON.parse(value)); + }); + resolve(items); + } catch (e) { + reject(e); + } + }); + ``` + +>**以上是我在使用AsyncStorage进行批量数据查询的一些思路,大家根据实际情况进行调整。** + + + + +D10:优化切换动画卡顿的问题(2016-8-31) +------ +使用API InteractionManager,它的作用就是可以使本来JS的一些操作在动画完成之后执行,这样就可确保动画的流程性。当然这是在延迟执行为代价上来获得帧数的提高。 +```javascript + InteractionManager.runAfterInteractions(()=>{ + //...耗时较长的同步任务... + //更新state也需要时间 + this.setState({ + ... + }) + //获取某些数据,需要长时间等待 + this.fetchData(arguements) + }) +``` D9:动态属性名&字符串模板(2016-8-30) ------ 在 ES6+ 中,我们不仅可以在对象字面量属性的定义中使用表达式,还有使用使用字符串模板: @@ -765,6 +1083,7 @@ import langsData from '../../../res/data/langs.json' [0]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment - +[1]: http://stackoverflow.com/questions/29322973/whats-the-best-way-to-add-a-full-screen-background-image-in-react-native +[2]: https://github.com/facebook/react-native/issues/4598#issuecomment-162328501 From b1976333dad9b143af24df6d7d40fcba3136f20d Mon Sep 17 00:00:00 2001 From: Gemmily Date: Wed, 14 Sep 2016 09:50:01 +0800 Subject: [PATCH 2/2] update update --- .../Readme.md" | 1 + 1 file changed, 1 insertion(+) diff --git "a/React Native \346\257\217\346\227\245\344\270\200\345\255\246/Readme.md" "b/React Native \346\257\217\346\227\245\344\270\200\345\255\246/Readme.md" index fa0f040..5109e4e 100644 --- "a/React Native \346\257\217\346\227\245\344\270\200\345\255\246/Readme.md" +++ "b/React Native \346\257\217\346\227\245\344\270\200\345\255\246/Readme.md" @@ -42,6 +42,7 @@ ListView设计的时候,当需要动态加载非常大的数据的时候,下 - 只更新渲染数据变化的那一行 ,`rowHasChanged`方法会告诉ListView组件是否需要重新渲染当前那一行。 - 选择渲染的频率 ,默认情况下面每一个`event-loop`(事件循环)只会渲染一行(可以同pageSize自定义属性设置)。这样可以把大的工作量进行分隔,提供整体渲染的性能。 + D18:ReactMethod的参数类型(2016-9-14) ------ `@ReactMethod`方法中传的参数必须是JavaScript和Java相互对应的。