React Native学习之路(9) - 注册登录验证的实现 + (用Fetch实现post请求) + (倒计时验证码)+(父子组件通信)+(asyncStorage异步存储) +(TextInput文本输入框)

(1)TextInput文本输入框

TextInput属性
  • (1) keyboardType :设置键盘类型(决定使用哪种键盘)
'email-address' : 邮箱键盘
 'numeric'  :数字键盘
 'phone-pad' :
  • (2) secureTextEntry :如果为true,文本框会遮住之前输入的文字,这样类似密码之类的敏感文字可以更加安全。默认值为false。( secure安全的意思 ) ( entry输入的意思 )
  • (3) placeholder :在文本输入之前提示用户文本框功能,也就是占位文字
  • (4) placeholderTextColor:占位字符串的文本颜色
  • (5) autoFocus:如果为true,在componentDidMount后会获得焦点。默认值为false。
  • (6) selectionColor :设置输入框高亮时的颜色(在iOS上还包括光标)
  • (6) editable:如果值为假,文本是不可编辑,默认值为真7
  • (7) maxLength :限制文本框中最多的字符数。使用这个属性而不用JS逻辑去实现,可以避免闪烁的现象。
  • (8) multiline:如果值为真,文本输入可以输入多行,默认值为假 ( multiline:多线路的 )
  • (9) onFocus :当文本框 (获得)焦点的时候调用此回调函数。
  • (10) onBlur :当文本框 (失去) 焦点的时候调用此回调函数。
  • (11) onChange:当文本框内容变化时调用此回调函数
  • (12) onChangeText:当文本框内容变化时调用此回调函数。改变后的文字内容会作
    为参数传递
 onChangeText={ (text) => {
                            this.setState({
                                phoneNumber: text   
                            })    //当文本框内容发生改变时,将文本框中输入的字符传给state
                        } }
  • (13) onEndEditing :当文本输入结束后调用此回调函数。
  • (14) inlineImageLef :指定一个图片放置在左侧。
  • (15) androidinlineImagePadding :给放置在左侧的图片设置padding样式。
  • (16) autoCapitalize :控制TextInput是否要自动将特定字符切换为大写:
 'characters': 所有的字符。
 'words': 每个单词的第一个字符。
 'sentences': 每句话的第一个字符(默认)。
' none': 不自动切换任何字符为大写。

(2) Fetch中的post请求

(1) JSON.parse() :

解析一个JSON字符串,可选地转换生成的值及其属性,并返回值。( 属性:值)( key:value )

换一种说法是:JSON.parse() 方法解析一个JSON字符串,构造由字符串描述的JavaScript值或对象。可以提供可选的reviver函数以在返回之前对所得到的对象执行变换。

(2) JSON.stringify()

返回与指定值相对应的一个JSON字符串,可选地仅包含某些属性或以用户定义的方式替换属性值。

// 将字符串JSON格式化
JSON.parse(responseData)

// 将JSON数据转化为字符串
JSON.stringify(responseData)
 //更新数据源
    this.setState({
      dataSource:this.state.dataSource.cloneWithRows(JSON.parse(responseData).data)
    });

(3) Post请求

执行POST提交,我们可以将method属性值设置为post,并且在body属性值中设置需要提交的数据。

fetch('https://mywebsite.com/endpoint/', {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    firstParam: 'yourValue',
    secondParam: 'yourOtherValue',
  })
})
-------------------------------------
译注:如果你的服务器无法识别上面POST的数据格式,那么可以尝试传统的form格式,示例如下:
fetch('https://mywebsite.com/endpoint/', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
  },
  body: 'key1=value1&key2=value2'
})
-------------------------------------

POST请求实例:

 fetch("http://rapapi.org/mockjs/22101/api/u/signup",{
            method:'POST',
            headers:{
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            body:JSON.stringify( 'phoneNumber': 'phoneNumber1' )
        }).then( (response) =>   response.json()   )
          .then( (data)=> {
            console.log(data.success)
            if(data && data.success){
                _this.showVerifyCode();
            }else{
                alert('发送验证码失败');
            }
        }).catch( (err) => {
            alert('获取验证码失败');
        })

http://www.cnblogs.com/keyi/p/6721710.html
http://www.jianshu.com/p/7c097051b5dc
http://www.51xuediannao.com/javascript/fetchdyf_fetchxydajaxqqfa__1142.html
http://blog.csdn.net/blueheart20/article/details/45174399
https://zhidao.baidu.com/question/7345375.html
iOS9对https的调整,需要在项目的info.plist添加Key:NSAllowsArbitraryLoads,具体方法看http://www.cnblogs.com/shaoting/p/5148323.html

(这里有个巨坑)http://blog.csdn.net/haoranli/article/details/60960858

   {
              this.state.codeSent
               ? <TouchableNativeFeedback  onPress={ this._submit }>
                      <Text style={ styles.btn}>登陆</Text>
                      </TouchableNativeFeedback>
                :
                  <TouchableNativeFeedback    onPress= { this._sendVerifyCode.bind(this) }>
                        <Text style={ styles.btn}>获取验证码</Text>
                         </TouchableNativeFeedback>
   }
如果不用bind(this)会出现报错

·

(4)验证码倒计时 setInterval() 和 clearInterval()

    
    coutDown() {
        this.setState({
            MainTime:60,
            MainTimeTitle: ''
        });
        this.bb = setInterval( () => {
            var aa = this.state.MainTime - 1;
            if( aa ===0){
                clearInterval( this.bb );
                this.setState({
                    MainTime:'',
                    MainTimeTitle: '重新获取'
                })}else{
                    this.setState({
                        MainTime: aa,
                        MainTimeTitle: ''
                    })
                }
        },1000)
    }
-------------------------------------
 <Text
         onPress={ this.coutDown.bind(this) }
          style={ styles.time}
 >{this.state.MainTime}{this.state.MainTimeTitle}
 </Text>

http://www.jianshu.com/p/819259d09609

(踩坑) :这样写的话会有个警告(如下,如图):


countDown()中的bb方法一直在执行

(解决方法)如下:

Waring: Can only update a mounted or mounting component. 

分析:可以看到在 countdown方法中每秒中调用一次bb方法去递减秒数,
当组件unmounted之后这个timer并没有停止,所以出现了上面的问题。

--------------------------------------------------------
解决方法:
将每次setInterval返回的ID保存起来,在componentWillUnmount方法中clearInterval
--------------------------------------------------------

完整代码:
    //组件将被卸载
    componentWillUnmount() {
        clearInterval(this.state.timeId)
    }
    //倒计时
    coutDown() {
        this.setState({
            MainTime:60,
            MainTimeTitle: ''
        });
        this.bb = setInterval( () => {
            var aa = this.state.MainTime - 1;
            if( aa ===56 ){
                clearInterval( this.bb );
                this.setState({
                    MainTime:'',
                    MainTimeTitle: '重新获取'
                })}else{
                    this.setState({
                        MainTime: aa,
                        MainTimeTitle: ''
                    })
                }
        },1000)
        this.setState({
            timeId: this.bb
        });
    }

http://blog.csdn.net/tujiaw/article/details/58238975

(5) 提交手机号和验证码

(1) 登陆按钮触发事件:

       {
                        this.state.codeSent
                        ? <TouchableNativeFeedback  onPress={ this._submit.bind(this) }>
                            <Text style={ styles.btn}>登陆</Text>
                            </TouchableNativeFeedback>
                        :
                         <TouchableNativeFeedback    onPress= { this._sendVerifyCode.bind(this) }>
                                <Text style={ styles.btn}>获取验证码</Text>
                          </TouchableNativeFeedback>
       }

(2) 登陆函数

_submit(){
        var that =  this;
        var loginPhoneNumber = this.state.phoneNumber;
        var loginVerifyCode = this.state.verifyCode;
        // console.log(loginPhoneNumber);
        // console.log(loginVerifyCode);
        if(!loginPhoneNumber || !loginVerifyCode ){
            return alert( 手机号或者验证码错误 );
        }else{
            fetch("http://rapapi.org/mockjs/22101/api/u/verify",{
                method:'POST',
                header: {
                    'Accept':'application/json',
                    'Content-Type':'application/json'
                },
                body: JSON.stringify({
                    'phoneNumber':'loginPhoneNumber',
                    'verifyCode': 'loginVerifyCode'
                })
            }).then( (response) => response.json() )
              .then((data) => {
                if(data && data.success){
                    // console.log(data)
                    // console.log(data.success)
                    // console.log( MOCK.mock(data) )
                    var data = MOCK.mock(data).data;
                    var stringify = JSON.stringify(data);
                    console.log(stringify);
                    // console.log(data.success)    //值是true
                    // that.props.afterLogin(stringify);
                    // console.log(data)
                    that.props.afterLogin(stringify);

                }else{
                    alert('发送验证码失败22222222222');
                }
              })
              .catch( (err) => {
                  alert('获取验证码失败333333333333');
              })
        }
    }

(3) 子组件传值给父组件

  _afterLogin(user) {
        var that = this;
        // user = JSON.stringify(user);
        AsyncStorage.setItem('user',user)
            .then( ()=> {
                console.log( AsyncStorage.getItem(user) )
                that.setState({
                    logined: false,
                    user: user
                })
                console.log(that.state.logined)
            })
        // this.setState(user)
    }


    render(){
        console.log( this.state.logined );   //true

        if(this.state.logined) {
            return <Login afterLogin={ this._afterLogin.bind(this) }/>;
        };
        return(
        <Go></Go>
        )
    }

这里可以理解为,父组件传递一个方法给子组件,子组件将(值)作为参数返回给父组件,父组件回调
http://blog.csdn.net/hehe0705/article/details/65631768

效果图:


20170724142429.gif

(6) AsyncStorage异步存储

AsyncStorage是一个简单的、异步的、持久化的Key-Value存储系统,它对于App来说是全局性的。它用来代替LocalStorage。

  • AsyncStorage.getItem() :存值


    QQ截图20170724144623.png

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 67,336评论 12 114
  • 《裕语言》速成开发手册3.0 官方用户交流:iApp开发交流(1) 239547050iApp开发交流(2) 10...
    叶染柒丶阅读 5,090评论 4 10
  • 《ilua》速成开发手册3.0 官方用户交流:iApp开发交流(1) 239547050iApp开发交流(2) 1...
    叶染柒丶阅读 2,821评论 0 5
  • 点击查看原文 Web SDK 开发手册 SDK 概述 网易云信 SDK 为 Web 应用提供一个完善的 IM 系统...
    layjoy阅读 5,206评论 0 11
  • 今日得到 1.干草堆里找一根不存在的针,成功人士坚持的时间是平常人的五倍多…… 赢家做事情不轻言放弃的能力和习惯都...
    Pheebs阅读 29评论 0 0