React Native 语法指南

作者: Gooooood | 来源:发表于2016-06-12 14:51 被阅读11173次

    React Native真的是越来越流行,没使用React Native开发项目都不好意思说自己是搞客户端开发的。对于纯Native开发者来说,刚上手React Native有一定的适应期,如果JavaScript也不熟练的话那就更悲催了。React Native涉及ES6,React语法,JSX,前端调试,Native客户端等知识,本文简单总结了React Native开发中一些知识点。算是在学习中的积累。

    Component


    Component:组件,使用React.createClass或者extends React.Component创建的类为组件。
    Element:元素或者可以说是组件的实例,使用<Label />或者let label = new Label()创建的为实例。

    对于定义组件,React以前版本的写法(ES5):

    var Lable  = React.createClass({
    
        render(){
        
        }
    });
    

    React最新的写法(ES6):

    class Label extends React.Component{
        render(){
        }
    }
    

    props与state


    props属性:组件可以定义初始值,自己不可更改props属性值,只允许从父组件中传递过来:

    // 父组件
    class MainComponent extends React.Component{
        render(){
            return(<Label name="标题栏">);
        }
    }
    
    // 子组件
    class Label extends React.Component{
        render(){
            return(<Text>{this.props.name}</Text>);
        }
    }
    

    父组件向Label传递name="标题栏"的props属性,在Label中使用this.props.name引用此属性。

    state属性:组件用来改变自己状态的属性,通常使用setState({key:value})来改变属性值,不能使用this.state.xxx来直接改变,setState({key:value})方法会触发界面刷新。

    对于经常改变的数据且需要刷新界面显示,可以使用state。对于不需要改变的属性值可以使用props。React Native建议由顶层的父组件定义state值,并将state值作为子组件的props属性值传递给子组件,这样可以保持单一的数据传递。

    在以前版本的React中定义state,props可以使用生命周期方法 getInitialState()getInitialState():

    var Label = React.createClass({
        getInitialState(){
            key:value,
            ...
        },
        getInitialProps(){
            key:value,
            ...
        },// 这种写法需要有,不要使用;
        render:funation(){
            
        }
    });
    

    在最新版本的React可以使用构造函数替代getInitialState(),getInitialState()方法定义初始值:

    class Label extends React.Component{
       constructor(props) {
           super(props);
           this.state = {
               time: '2016',
               city: '上海',
           };
           this.props = {
               name:'标题',
           };
       }
    }
    

    默认props与props校验


    class Label extends React.Component{
       constructor(props) {
           super(props);
       }
    
      // 默认props
      static defaultProps = {
         city: '南京',
         index: 12,
      }
       
      // propTypes用于验证转入的props,当向 props 传入无效数据时,JavaScript 控制台会抛出警告
      static propTypes = {
         city: React.PropTypes.string.isRequired,
         index: React.PropTypes.number.isRequired,
      }
    
      state = {
         city: this.props.city,
         index:this.props.index,
      }
    }
    
    // or
    
    class Label extends React.Component{
       constructor(props) {
           super(props);
       }
    }
    
    // 默认props
    Label.defaultProps = {
       city: '南京',
       index: 12,
    }
    
    // propTypes用于验证转入的props,当向 props 传入无效数据时,JavaScript 控制台会抛出警告
    Label.propTypes = {
       city: React.PropTypes.string.isRequired,
       index: React.PropTypes.number.isRequired,
    }
    

    生命周期


    我们把组件从装载,到渲染,再到卸载当做一次生命周期,也就是组件的生存状态从装载开始到卸载为止,期间可以根据属性的变化进行多次渲染。

    生命周期的三种状态:

    • Mounting:装载,
    • Updating:渲染
    • Unmounting:卸载
    componentWillMount(),组件开始装载之前调用,在一次生命周期中只会执行一次。
    componentDidMount(),组件完成装载之后调用,在一次生命周期中只会执行一次,从这里开始就可以对组件进行各种操作了,比如在组件装载完成后要显示的时候执行动画。
    componentWillUpdate(object nextProps, object nextState),组件属性更新之前调用,每一次属性更新都会调用
    componentDidUpdate(object prevProps, object prevState),组件属性更新之后调用,每次属性更新都会调用
    componentWillUnmount(),组件卸载之前调用
    

    组件属性更改时会调用以下方法,在一次生命周期中可以执行多次:

    componentWillReceiveProps(object nextProps),已加载组件收到新的参数时调用
    shouldComponentUpdate(object nextProps, object nextState),组件判断是否重新渲染时调用
    

    页面跳转


    初始化第一个页面:

    import SeatPageComponent from './SeatPageComponent';
    import MainPageComponent from './MainPageComponent';
    import TrainListComponent from './TrainListComponent';
    
    class MainPage extends React.Component {
        render() {
            let defaultName = 'MainPageComponent';
            let defaultComponent = MainPageComponent;
            return (
                <Navigator
                    // 指定默认页面
                    initialRoute={{ name: defaultName, component: defaultComponent }}
                    // 配置页面间跳转动画
                    configureScene={(route) => {
                        return Navigator.SceneConfigs.VerticalDownSwipeJump;
                    }}
                    // 初始化默认页面
                    renderScene={(route, navigator) => {
                        let Component = route.component;
                        // 将navigator作为props传递到下一个页面
                        return <Component {...route.params} navigator={navigator} />
                    }} />
            );
        }
    }
    

    跳转到下一页面:

    jumpToNext(){
          const { navigator } = this.props;// 由上一个页面传递过来
          if(navigator) {
              navigator.push({
                  name: 'SeatPageComponent',
                  component: SeatPageComponent,// 下一个页面
              });
          }
    }
    

    返回上一个页面:

     _back(){
         const { navigator } = this.props;
         if(navigator) {
             navigator.pop();
         }
     }
    

    页面间通信


    例如:从A页面打开B页面
    A通过route.params将参数传递给B:

    jumpToNext(){ 
        const { navigator } = this.props;// 由上一个页面传递过来
        if(navigator) { 
            navigator.push({ 
                name: 'SeatPageComponent', 
                component: SeatPageComponent,// 下一个页面 
                params: { // 需要传递个下一个页面的参数,第二个页面使用this.props.xxx获取参数
                    id: 123,
                    title: this.state.title, 
                },
            });
         }
    }
    

    A通过route.params传递回调方法或者A的引用来让B将数据传回给A:

    
    // A页面
    jumpToNext(){ 
        const { navigator } = this.props;// 由上一个页面传递过来
        if(navigator) { 
            let that = this;// this作用域,参见下文函数绑定
            navigator.push({ 
                name: 'SeatPageComponent', 
                component: SeatPageComponent,// 下一个页面 
                params: { // 需要传递个下一个页面的参数,第二个页面使用this.props.xxx获取参数
                    title: '测试',
                    getName: function(name) {that.setState({ name: name })}
                },
            });
         }
    }
    
    // B页面
     _back(){
         const { navigator } = this.props;
         if(this.props.getName){
             this.props.getName('测试');
         }
         if(navigator) {
             navigator.pop();
         }
     }
    
    

    组件间通信


    父组件-->子组件, 使用props,父组件向子组件传递props

    // 父组件
    class MainComponent extends React.Component{
        render(){
            return(<Label name="标题栏">);
        }
    }
    
    // 子组件
    class Label extends React.Component{
        render(){
            return(<Text>{this.props.name}</Text>);
        }
    }
    

    子组件-->父组件, 父组件在创建子组件时传递回调方法

    // 父组件
    class MainComponent extends React.Component{
        constructor(props) {
            super(props);
            this.state = {
                name: '测试',
            };
        }
      
        // 回调方法
        getName(str){
             this.setState({name:str});
        }
    
        render(){
            return(<Label name="标题栏" getName={getName}/>);
        }
    }
    
    // 子组件
    class Label extends React.Component{
        render(){
            return(
                <View>
                      <TouchableOpacity onPress={()=>this._onPress()}>
                              <Text>点我,{this.props.name}</Text>
                      </TouchableOpacity>
                </View>);
        }
    
        _onPress(){
              if(this.props.getName){
                  this.props.getName('测试')
              }
        }
    }
    

    非父子关系的组件,即没有任何嵌套关系的组件, 可以引入订阅源(js-signals, PubSubJS),监听订阅事件。例如,在生命周期方法中addEventListener(),removeEventListener(),在合适时机setState()。

    ECMAScript


    ES6中函数的写法:

    class Label extends React.Component{
        doSomething(){
            //...
        }// 不要使用逗号或者分号作为结尾
    }
    

    key:value形式定义函数的写法:

    var Label = React.createClass({
        doSomething:funation(){
            //......
        },// 需要使用逗号作为结尾,不能使用分号
        doSomething2:function(){
            //......
        },
    });
    

    函数绑定

    class Label extends React.Component{
    
        // 有函数
        sayHello(str){
            console.log(str)
        }
    
        // 在onPress中使用箭头函数调用
        // onPress={() => this.sayHello('Hello')}
        
        // 等同于
        //onPress={sayHello('hello').bind(this)} 
    
        // 等同于
        // onPress={print('hello',this)}
    
        render(){
            return (
                  <View>
                       <TouchableOpacity onPress={() => this.sayHello('Hello')}>
                              <Text>点我</Text>
                       </TouchableOpacity>
                  </View>
            )
        }
    
        function print(str,this){
            let that = this;// 注意这里this的生命周期
            function say(str){
                that.sayHello(str)// 此处不能再使用this
            }
            say(str);
        }
    }
    

    Tips


    require,import:javascript的模块管理工具,管理各个模块之间的引用,解决javascript异步加载的问题,解决js写成多个文件后浏览器加载缓慢的问题。

    JavaScript中没有private,public的概念
    使用_开头的方法代表private方法,不适用则表示public方法

    class Label extends Component{
        // private 函数
        _doSomething(){
            //......
        }
        
        // public 函数
        doSomething(){
            //......
        }
    }
    

    参考资料
    Reactjs中文教程
    极客学院React教程
    ECMAScript语法
    JavaScript模块系统
    require.js
    Navigator
    结合ES6+开发React
    React组件通信

    相关文章

      网友评论

      • 傍山而王:刚才在学RN,但是 onPress 事件总是报错,看了你这个文章,恍然大悟,是调用方法不对。多谢多谢。RN 呐,果然是万物皆函数啊。
      • d96aa8b37e5f:报错无法获取到‘x’的值,小圆点可以动,图片却不能动
      • Smither:感谢,写得很细致。
      • 照亮黑夜的曙光:学习了 只会iOS原生开发 最近在看RN 不懂语法还真是看得很懵逼
      • 4ed9c19e6074:入门,为什么有的return后面接{} 有的接()
      • 薐驚:作者可否给个demo地址
      • FKCrazy:有用
      • Jack_zz:这个语法看的我脸懵逼~~兄弟给个qq呗,我看了你的博客,我最近也在弄hexo(有点地方还没搞清楚) 和这个RN(纯新手) 我是搞ios的现在烂大街了,想学点新的东西啊~~~~~

      本文标题:React Native 语法指南

      本文链接:https://www.haomeiwen.com/subject/svwfdttx.html