RN-笔记

  • 创建指定RN版本的工程
react-native init MyApp --version 0.44.3。注意版本号必须精确到两个小数点。
  • 倒计时 (系统自带的)
//定时器: 隔2s切换到Main
setTimeout( ()=>{
            //页面的切换
            this.props.navigator.replace({
                component:Main, //具体路由的版块
            });
 } ,2000);
  • 按钮 Switch的状态切换
//!this.state.isOn 取反,切换状态
// onValueChange={()=>{this.setState({isOn:!this.state.isOn})}}
<Switch value={this.state.isOn === true} onValueChange={()=>{this.setState({isOn:!this.state.isOn})}} style={{marginRight:8}}/>
  • ScrollView的吸顶效果
 <ScrollView
          style={styles.scrollViewStyle}
          contentInset={{top:-200}}
          contentOffset = {{y:200}}
 >
</ScrollView>
吸顶效果
  • 遍历时,控件一定要加 key={i}
    //页码指示器
    renderIndicator(){
        //指示器数组
        var indicatorArr = [], style;
        //遍历创建组件
        for (var i=0;i<2;i++){
            //设置圆点样式
            style = (i === this.state.activePage) ? {color:'orange'} : {color:'gray'}
            indicatorArr.push(
                //                  一个数组里面有多个样式
                <Text key={i} style={[style,{fontSize:30}]}>•</Text>
            );
        }
        return indicatorArr;
    }
  • 用ListView实现九宫格布局
    通常情况下,我们对ListView的操作是纵向的,如果是横向的,则需要设置ListView的contentContainerStyle属性,添加flexDirection:‘row’让多个ListView在同一行显示,而且通过flexWrap:'wrap'进行换行。
    contentViewStyle:{
        //设置主轴的方向
        flexDirection:'row',
        //多个cell在同一行显示
        flexWrap:'wrap',
        //宽度
        width:Dimensions.get('window'),
    },
全局变量
var {width} = Dimensions.get('window');
//全局的变量
var cols = 5;
var cellW = Platform.OS == 'ios' ? 70 : 50;
var cellH =  70;
var vMargin = (width-cellW*cols) / (cols + 1);
渲染
render(){
        return(
            <ListView
                dataSource = {this.state.dataSource}
                renderRow = {this._renderRow}
                contentContainerStyle = {styles.contentViewStyle}
                scrollEnabled = {false}
            />
        );
    },
样式
const styles = StyleSheet.create({
    contentViewStyle:{
        //设置主轴的方向
        flexDirection:'row',
        //多个cell在同一行显示
        flexWrap:'wrap',
        //宽度
        width:width,
    },
    cellStyle:{
        width:cellW,
        height:cellH,
        justifyContent:'center',
        alignItems:'center',
        marginTop:10,
        marginLeft:vMargin,
    },
    titleStyle:{
        color:'gray',
        fontSize:Platform.OS == 'ios' ? 14: 10
    }
});
效果
美团滚动菜单
  • 替换字符串的内容

下面的图片url中,包含有/w.h/字符,需要前端传递给后台具体的尺寸,然后返回对应尺寸的图片

"imageurl": "http://p0.meituan.net/w.h/groupop/b8fb2def2c0063c9acabed6cbf1c65449452.png"

js中的做法

    //处理图像的尺寸
    dealWithImgUrl(url){
        //url.search('w.h') 如果找到,则返回正数;没有找到,则返回 -1;
        if (url.search('w.h') == -1){
            //没有找到, 正常返回
            return url;
        }else {
            //把'w.h'替换成具体的尺寸
            return url.replace('w.h',64.43);
        }
    }
  • 对象序列化: JSON.stringify(result)
var result = {'name':'张三','age':'25'}
//对象序列化
JSON.stringify(result) 
  • 解析一个JSON字符串 : JSON.parse()
resolve(JSON.parse(result));
一般用作AsyncStorage等获取的是json字符串格式的数据,需要转换成Json格式

一般用作fetch数据请求中

 post(url, data) {
        fetch(url, {
            method: 'POST',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
            },
            //将传递过来的参数对象序列化
            body: JSON.stringify(data)
        })
            .then(response=>response.json())
            .then(result=> {
                this.setState({
                    //转换成了json字符串格式,在实际开发中不用转,直接可以用
                    //该界面主要用作通过<Text>标签把请求结果显示出来
                    result: JSON.stringify(result)
                })
            })
            .catch(error=> {
                this.setState({
                    result: JSON.stringify(error)
                })
            })
    }
  • 设置阴影

elevation number(限Android)使用Android原生的 elevation API来设置视图的高度(elevation)。这样可以为视图添加一个投影,并且会影响视图层叠的顺序。此属性仅支持Android5.0及以上版本。

        //阴影安卓和iOS有别:
        //IOS
        shadowColor:'red',
        shadowOffset:{width:1,height:1},
        shadowOpacity:0.4,
        shadowRadius:1,
        //安卓
        elevation:2,
  • try catch 抛出异常
fetch(){

        return new Promise((resolve,reject)=>{

            AsyncStorage.getItem(this.flag,(error,result)=>{

                if (error){
                    reject(error);
                }else {
                    if (result){
                        //解析有可能会出错,抛出异常
                        try {
                            //转成JSON格式
                            resolve(JSON.parse(result));
                        } catch (e){
                            //出错
                            reject(e);
                        }
                    }
                }
            })
        })
    }
  • 使用map遍历
this.state.languages.map((result,i,array)=>{
       let lan = array[i];
       return lan.checked ? <PopularTab tabLabel={lan.name}>{lan.name}</PopularTab> : null;
})
  • 获取数组中元素的索引
let index = this.dataArray.indexOf(item);
  • DeviceEventEmitter 事件儿发射器]

添加通知

   componentDidMount(){
        this.listener=DeviceEventEmitter.addListener('showToast',(text)=>{
           this.toast.show(text,DURATION.LENGTH_LONG);
        });
    }

移除通知

    componentWillUnmount(){
        this.listener&&this.listener.remove();
    }

发送通知 (在需要发送通知的地方发送通知)

DeviceEventEmitter.emit('showToast','显示缓存数据');
  • TextInput 注意

默认给TextInput设置要显示的内容,如果设置value='xxx',会导致输入框无法输入!

<TextInput
      style={styles.input}
      value={URL}
      onChangeText={text=>this.text=text}
/>

应设置defaultValue='xxx',这样就可以正常输入了

<TextInput
      style={styles.input}
      defaultValue={URL}
      onChangeText={text=>this.text=text}
/>
  • react-native-htmlview的使用
//用p标签包括以下,也可以换用别的标签
let description = '<p>'+this.props.data.description+'</p>';
<HTMLView
       value={description}
       stylesheet={{ //设置标签的样式
           p:styles.description,
           a:styles.description,
        }}
       onLinkPress={(url) => {}}
/>
const styles = StyleSheet.create({
    description:{
        fontSize:14,
        marginBottom:2,
        color:'#757575',
    },
})
  • ES6和ES5的不一样
export default class CustomKeyPage extends Component {
    constructor(props) {
        super(props);
       //可以往里面存东西,但是不会触发更细状态机
        this.changeValues = [];
       //会触发更新状态机
        this.state={
            dataArray:[],
        }
    }
}
  • 报错: React.Children.only expected to receive a single React element child.

则需要用View把这些组件包裹起来

<View style={{flexDirection:'row'}}>
       <Image source={require('./images/ic_sort.png')}/>
       <Text>{this.props.data.name}</Text>
</View>
  • undefined is not an object (evaluating 'this.props.navigator.push')

报这样的错误,需要检查下各个界面的延展属性有木有传!!!

  • this.setState is not a function. (In 'this.setState({ isVisible: false})', 'this.setState' is undefined)

有时候第三方插件采用的ES5的写法,导致程序崩溃,先检查方法函数是否采用的ES5,再改成ES6.

  • 按钮状态的切换

设置this.state

this.state={
         //默认未选中
         isFavorite:false,   
         //默认图片
         favoriteIcon:require('../../res/images/ic_unstar_transparent.png'),
}

创建按钮

        let favoriteButton = <TouchableOpacity
            onPress={()=>this.onPressFavorite()}
        >
            <Image
                style={{width:22,height:22,tintColor:'#2196F3'}}
                source={this.state.favoriteIcon}
            />
        </TouchableOpacity>

按钮点击,状态切换

    onPressFavorite(){
        this.setState({
            //this.state.isFavorite状态取反
            isFavorite:!this.state.isFavorite,
            //显示图片切换
            favoriteIcon:!this.state.isFavorite ? require('../../res/images/ic_star.png'):require('../../res/images/ic_unstar_transparent.png'),
        });
    }
按钮状态切换
  • 当props发生变化时执行,初始化render时不执行

当props发生变化时执行,初始化render时不执行,在这个回调函数里面,你可以根据属性的变化,通过调用this.setState()来更新你的组件状态,旧的属性还是可以通过this.props来获取,这里调用更新状态是安全的,并不会触发额外的render调用

    //当数据状态不能及时刷新时,调用此方法
    componentWillReceiveProps(nextProps){
        this.setFavoriteState(nextProps.projectModel.isFavorite);
    }

    setFavoriteState(isFavorite){
        this.setState({
            isFavorite:isFavorite,
            favoriteIcon:isFavorite ? require('../../res/images/ic_star.png'):require('../../res/images/ic_unstar_transparent.png'),
        });
    }
  • item.id.toString() 转成字符串
  • 事件的点击等操作方法前加on
//onPress={()=>this.onRightButtonClick()},onRightButtonClick前面加on
<TouchableOpacity
        onPress={()=>this.onRightButtonClick()}
>我是按钮</TouchableOpacity>

方法实现

onRightButtonClick(){
        alert('我被点击了');
}
  • multiGet ====> AsyncStorage 通过多个key获取数据
//参数 keys:数组
AsyncStorage.multiGet(keys,(err,stores)=>{
                        try {
                            stores.map((result,i,store)=>{
                                let value = store[i][1];
                                if (value) items.push(value);
                            })
                            resolve(items);
                        }catch (e){
                            reject(e);
                        }
                    });
  • 通知的使用

监听页面

   //添加通知
   componentDidMount() {
        this.listener = DeviceEventEmitter.addListener('favoriteChanged_popular', () => {
            this.isFavoriteChanged=true;
        });
        this.loadData();
    }
    //记得移除通知
    componentWillUnmount(){
        if (this.listener) {
            this.listener.remove();
        }
    }

在需要发送通知的地方发送通知

 DeviceEventEmitter.emit('favoriteChanged_popular');
  • 定义一些常量
定义一些常量
/**
 * 定一些常量
 * 更多菜单
 * */

//导出标识
export const MORE_MENU={
    Custom_Language:'Custom Language',
    Sort_Language:'Sort Language',
    Custom_Key:'Custom Key',
    Sort_key:'Sort Key',
    Remove_Key:'Remove Key',
    About_Author:'About Author',
    About:'About',

}

在使用的地方这样引入

import {MORE_MENU} from '../../common/MoreMenu'

这样使用

//直接调用
MORE_MENU.About
//如下面示例
<TouchableHighlight
          onPress={()=>this.onClick(MORE_MENU.About)}
>我是按钮</TouchableHighlight>
  • 定义全局的样式类
定义一个全局的样式

代码如下:

/**
 * 全局样式
 * @flow
 */
import {
    Dimensions
}from 'react-native'
const {height, width} = Dimensions.get('window');

//导出全局样式
module.exports ={
    line: {
        height: 0.4,
        opacity:0.5,
        backgroundColor: 'darkgray',
    },
    root_container:{
        flex: 1,
        backgroundColor: '#f3f3f4',
    },
    backgroundColor: '#f3f3f4',
    nav_bar_height_ios:44,
    nav_bar_height_android:50,
    window_height:height,
};

使用的地方,先导入

import GlobalStyles from '../../../res/styles/GlobalStyles'

调用方法:

<View style={GlobalStyles.line}></View>
  • 公共类里面定义表示,用于区分不同的组件调用
定义标识

在别的类中,调用该组件

调用该实例的render()方法
  • Linking 打开浏览器、邮箱或者其它的应用

如果想在打开链接前先检查是否安装了对应的应用,则调用以下方法:

//以发送邮箱为例
//打开邮箱,由于模拟器上没有安装邮箱,故无法打开
var url='mailto://1047912930@qq.com';
Linking.canOpenURL(url).then(supported => {
  if (!supported) {
    console.log('Can\'t handle url: ' + url);
  } else {
    return Linking.openURL(url);
  }
}).catch(err => console.error('An error occurred', err));
  • Map()函数
let map = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);
let arr = [...map.keys()]; // [1, 2, 3]

具体使用如下


实例化一个itemMap
添加k,v
  • async和await用法

要理解async和await的用法,首先要了解Task相关知识,这里不做说明,因为这不是本文的重点。
如果你已经对Task很了解,那么如何使用async和await,在此主要总结了以下三点:
1.只有在async方法里面才能使用await操作符;
2.await操作符是针对Task对象的;
3.当方法A调用方法B,方法B方法体内又通过await调用方法C时,如果方法C内部有异步操作,则方法B会等待异步操作执行完,才往下执行;但方法A可以继续往下执行,不用再等待B方法执行完。
使用如下:(省去了链式调用的繁琐)

    async updateFavorite(repositories){
        if (repositories) this.repositories = repositories;
        //等于空  直接return
        if (!this.repositories) return;
        if (!this.favoriteKeys){
            this.favoriteKeys = await this.favoriteDao.getFavoriteKeys();
        }
    }
  • 设置this.state要注意
constructor(props) {
        super(props);
       this.state={
            //默认值要为数组[],或者对象{},千万不能是null,(null会报错)
            dataSource:[],
        }
    }
  • StackNavigator 导航跳转
const { navigate } = this.props.navigation;
//点击调转
onPress={() => navigate('Detail', {
        //传值
        id: item.id,
        //回调
        callback: (data) => {
           this.setState({
               childState: data
                })
            }
})}

Detail页面显示

  static navigationOptions = {
    title: '详情页',
  };

没有回调 => 返回

onPress={()=>this.props.navigation.goBack()}

带有参数=>返回

const {state,goBack} = this.props.navigation;
<Text onPress={()=>{
             state.params.callback('假装是回传的内容');
             goBack();

               }}
>返回</Text>
  • AsyncStorage存储 只能存 "死的"字符串 (json字符串)
async componentDidMount() {
    const { state: { params: { id } } } = this.props.navigation;
    let textData, jsonData;
    //await 该函数执行完 才能往下接着执行
    //如果使用await componentDidMount()方法前要加 async
    textData = await AsyncStorage.getItem(id);

    if (textData) {
      // alert('数据来自本地');
    } else {
      const rawData = await fetch(`${api}/${id}`);
      textData = await rawData.text();
      // alert('数据来自服务器');
    }
    // title, summary
    // "images": {
    //   "small": "http://img3.doubanio.com/view/movie_poster_cover/ipst/public/p494268647.webp",
    //     "large": "http://img3.doubanio.com/view/movie_poster_cover/lpst/public/p494268647.webp",
    //     "medium": "http://img3.doubanio.com/view/movie_poster_cover/spst/public/p494268647.webp"
    // }
    // 反序列化: "死的"字符串 => "活的"对象
    jsonData = JSON.parse(textData);
    jsonData.image = jsonData.images.large.replace('webp', 'jpg');

    // 序列化: "活的"对象 => "死的"字符串
    // const textData = JSON.stringify(jsonData);
    AsyncStorage.setItem(id, textData);

    this.setState({
      data: jsonData,
      ready: true,
    });

    this.fetchVideo(jsonData.mobile_url);
  }
  • 复制到剪切板
Clipboard.setString('xxx');
  • 打开邮箱
Linking.openURL('mailto://1047912930@qq.com');
  • 给textInput设置paddingLeft:5,输入框的光标就会往右移动5px的距离
textInput: {
        flex: 1,
        paddingLeft: 5,//输入框的光标就会往右移动
    },
  • 让键盘隐藏(输入框失去焦点)

处理方式(一):
先定义该变量 dismissKeyboard

const {width, height} = Dimensions.get('window');       // 获取屏幕尺寸
const dismissKeyboard = require('dismissKeyboard');     // 获取键盘回收方法
// 第三方
import {PullList} from 'react-native-pull';

调用

  // 返回
    pop() {
        // 回收键盘
        dismissKeyboard();
        this.props.navigator.pop();
    }

处理方式(二):

先给输入框Input设置ref
<TextInput
     ref="input"
     onChangeText={text=>this.inputKeky=text} //将text赋值给this.inputKeky
     style={styles.textInput}
> </TextInput>

让输入框失去焦点

<TouchableOpacity
      onPress={()=> {
           this.refs.input.blur(); //让输入框失去焦点
           this.onRightButtonClick();
       } }
>搜索 </TouchableOpacity>
  • 另一种绑定ref方法

用的时候可以直接使用this.toast调用方法

<Toast ref={toast=>this.toast = toast}/>
  • 指示器ActivityIndicator的使用
       //当加载数据时显示指示器,加载完成后关闭指示器
       let listView=!this.state.isLoading?<ListView
            dataSource={this.state.dataSource}
            renderRow={(e)=>this.renderRow(e)}
        />:null;
        let indicatorView=this.state.isLoading?
            <ActivityIndicator
                style={styles.centering}
                size='large'//设置指示器的大小,是枚举值
                animating={this.state.isLoading}
            />:null;
        let resultView=<View style={{flex:1}}>
            {indicatorView}
            {listView}
        </View>

        //样式
        centering:{
              alignItems:'center',
              justifyContent:'center',
              flex:1, //一定要指定flex
         },
  • 取消网络请求

就像在网上买东西一样,卖家已经发货是无法取消订单的,但是我们可以在快递来的时候,选择拒收快递!

封装取消网络请求类

export default function 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}):resolve(error)
        })
    });
    //向调用者返回一个字典
    return {
        promise:wrappedPromise,
        //返回cancel方法,并将 hasCanceled_ 置为true
        cancel(){
            hasCanceled_=true;
        }
    }

}

在使用的类里面导入

import makeCancelable from '../util/Cancleable'

请求数据时调用

loadData(){
this.cancelable=makeCancelable(fetch(this.genFetchUrl(this.inputKeky)));
        this.cancelable.promise
            .then(response=>response.json())
            .then(responseData=>{
                ...
            }).catch(e=>{
                ...
        })

取消搜索

//在取消搜索的地方调用
this.cancelable.cancel();
  • 取消网络请求的应用

当获取网络请求的页面,当数据还未获取到时,用户选择返回上一级界面,这时,网络请求的页面还在请求数据,当获取到数据时,再上一级界面底部会显示警告,这时就需要在组件Will被卸载的方法中 "调用取消网络请求" .

componentWillUnmount(){
        //this.cancelable  判断this.cancelable是否为空
        this.cancelable&&this.cancelable.cancel();
    }
  • React-Native 支持GCD的
  • 在终端中切换到 当前文件某个目录
比如切换到iOS文件下执行一些操作
cd iOS /
  • 属性的声明 propTypes
具体参考贾鹏辉自定义 NavigationBar 内容
static propTypes = {
        name: PropTypes.string,
        ID: PropTypes.string.isRequired, //这个是必须的,不传值会报警告
    }
  • webView加载服务器返回的html标签
<WebView
        ```
       source={{html: this.state.html, baseUrl: ''}}
        ```
/>
  • 去除 Android 中输入框的下划线

那么 Android 中的 TextInput 的下划线是不是丑爆了?这边我们也来处理下它,直接使用 underlineColorAndroid 这个属性,让他为透明即可。

 underlineColorAndroid={'transparent'}
  • 获取Realm的路径

先获取到Documents的路径

  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  NSString *docDir = [paths objectAtIndex:0];
  NSLog(@"====Realm的存储路径:%@",docDir);

在Documents的路径下有一个default.realm的文件,该文件就是Realm的文件存储位置,可用Realm Borwser双击打开

  • FlatList滚动到某一行
this.listView.scrollToIndex({viewPosition: 0, index: 0});
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容