react-native 组件间通信

react native 中,组件间通信无非3种情况:

以DEMO为例,有2个组件Input和 ShowText 。

1、组件嵌套,即Input是ShowText的子组件,在组件间通信可以通过state进行。
2、组件为同级关系,即Input和ShowText都属于页面级别内的组件,这是常见的组件间通信,可各自提供接口进行通信,利用props进行
3、除了以上2种的关系外的组件,比如Input在一个Container组件内,页面级别只有2个组件Container和ShowText。这种情况下,可创建一个全局的通信类。在react-native的2014 example 中 都有这样的代码,这里就不再贴代码了。

源码可查看github:https://github.com/baofen14787/react-native-communicate-demo

第一种情况:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 */
'use strict';

var React = require('react-native');


var {
  StyleSheet,
  Text,
  View,
  TextInput
} = React;


var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});


var Input = React.createClass({

    handleUpdateChange(text) {
        this.props.updateChange(text);
    },


  render() {

    return (
        <TextInput onChangeText={(text) => this.handleUpdateChange(text)} style={{ width : 200, height: 40, borderColor: 'gray', borderWidth: 1}} />
    );
  }
});




var ShowText = React.createClass({

    getInitialState(){
      return {
        text : '我是文字'
      }
    },

    handleChange(textValue){
      this.setState({
        text: textValue
      });
    },

    render() {

        return (
          <View style={{flex : 1,justifyContent: 'center',alignItems: 'center',backgroundColor: '#F5FCFF'}}>
            <Text>{this.state.text}</Text>
            <Input updateChange={this.handleChange} />
          </View>
        );
    }
});

module.exports = React.createClass({

  render() {
    return (
      <View style={styles.container}>
        <ShowText />
      </View>
    );
  }
});

第二种情况:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 */
'use strict';

var React = require('react-native');


var {
  StyleSheet,
  Text,
  View,
  TextInput
} = React;


var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});


var Input = React.createClass({

    handleUpdateChange(text) {
        this.props.updateChange(text);
    },


  render() {

    return (
      <View style={{flex : 1,justifyContent: 'center',alignItems: 'center',backgroundColor: '#F5FCFF'}}>
        <TextInput onChangeText={(text) => this.handleUpdateChange(text)} style={{ width : 200, height: 40, borderColor: 'gray', borderWidth: 1}} />
      </View>
    );
  }
});




var ShowText = React.createClass({


    render() {

        return (
          <View style={{flex : 1,justifyContent: 'center',alignItems: 'center',backgroundColor: '#F5FCFF'}}>
            <Text>{this.props.text}</Text>
          </View>
        );
    }
});

module.exports = React.createClass({

  getInitialState(){
    return {
      text : '我是文字'
    }
  },

  handleChange(textValue){
    this.setState({
      text: textValue
    });
  },

  render() {
    return (
      <View style={styles.container}>
        <Input updateChange={this.handleChange} />
        <ShowText text={this.state.text} />
      </View>
    );
  }
});

reactjs 中 event 对象控制台输出null的问题

在 react 中输出 event 对象,在控制台查看是 null ,这对调试非常不友好。如图:

解决的办法很简单,在 console.log(event) 前使用event的 persist() 方法即可。

var Test = React.createClass({
        handleClick : function(e){
          e.persist()
          console.log(e);
            
        },

        render : function(){
           return (
                   <div onClick={this.handleClick}>我是DIV</div>
           )
        }

      });

      React.render(
              <Test />,
              document.getElementById('container')
      );

react native 中es6语法解析

解构赋值

var {
  StyleSheet,
  Text,
  View
} = React;

这句代码是ES6 中新增的解构(Destructuring)赋值语句。准许你获取对象的多个属性并且使用一条语句将它们赋给多个变量。

上面的代码等价于:

var StyleSheet = React.StyleSheet;
var Text = React.Text;
var View = React.View

再看几个例子,以前,为变量赋值,只能直接指定值:

var a = 1;
var b = 2;
var c = 3;

而ES6 允许这样写:

var [a, b, c] = [1, 2, 3];

更详细的内容可参看: 变量的解构赋值

箭头函数

React Native 里面经常会出现类似的代码:

ES6中新增的箭头操作符 => 简化了函数的书写。操作符左边为输入的参数,而右边则是进行的操作以及返回的值 Inputs=>outputs

举几个栗子感受下:

var array = [1, 2, 3];
//传统写法
array.forEach(function(v, i, a) {
    console.log(v);
});
//ES6
array.forEach(v => console.log(v));
var sum = (num1, num2) => { return num1 + num2; }
//等同于:
var sum = function(num1, num2) {
    return num1 + num2;
 };

更多详细内容请自行Google,或查看: https://www.imququ.com/post/arrow-function-in-es6.html

延展操作符(Spread operator)

这个 … 操作符(也被叫做延展操作符 - spread operator)已经被 ES6 数组 支持。它允许传递数组或者类数组直接做为函数的参数而不用通过apply。

var people=['Wayou','John','Sherlock'];
//sayHello函数本来接收三个单独的参数人妖,人二和人三
function sayHello(people1,people2,people3){
    console.log(`Hello ${people1},${people2},${people3}`);
}
//但是我们将一个数组以拓展参数的形式传递,它能很好地映射到每个单独的参数
sayHello(...people);//输出:Hello Wayou,John,Sherlock 

//而在以前,如果需要传递数组当参数,我们需要使用函数的apply方法
sayHello.apply(null,people);//输出:Hello Wayou,John,Sherlock 

而在 React 中,延展操作符一般用于属性的批量赋值上。在JSX中,可以使用…运算符,表示将一个对象的键值对与ReactElement的props属性合并。

var props = {};
  props.foo = x;
  props.bar = y;
  var component = <Component {...props} />;
  
//等价于
var props = {};
  props.foo = x;
  props.bar = y;
  var component = <Component foo={x} bar={y} />;

它也可以和普通的XML属性混合使用,需要同名属性,后者将覆盖前者:

var props = { foo: 'default' };
var component = <Component {...props} foo={'override'} />;
console.log(component.props.foo); // 'override'

更多详细信息: https://facebook.github.io/react/docs/jsx-spread.html

class

ES6中添加了对类的支持,引入了class关键字(其实class在JavaScript中一直是保留字,目的就是考虑到可能在以后的新版本中会用到,现在终于派上用场了)。JS本身就是面向对象的,ES6中提供的类实际上只是JS原型模式的包装。现在提供原生的class支持后,对象的创建,继承更加直观了,并且父类方法的调用,实例化,静态方法和构造函数等概念都更加形象化。

class PropertyView extends Component {
    render() {
        return (
            <View></View>
        )
    }
}

//等价于
var PropertyView = React.createClass({
    render() {
        return (
            <View></View>
        )
    }
})

方法定义(method definition)

ECMAScript 6中,引入了一种名叫方法定义(method definition)的新语法糖,相对于以前的完整写法,这种简写形式可以让你少写一个function键字.

React.createClass({
    render() {
        return (
            <View></View>
        )
    }
})

//等价于

React.createClass({
    render : function() {
        return (
            <View></View>
        )
    }
})

最后,推荐一个ES6的PPT,写得不错: http://khan4019.github.io/ES6/

react-native demo一例

前2周,fackbook发布了react-native , 一时间前端界异常兴奋。各种概念飞满天,俺作为前端一份子,也凑凑热闹。

花了2天时间,边看API边写代码,react-native 真是太新了,好多问题都google不到内容,来来去去都是官方文档,这2天下来,也算摸清了react-native的一些用法。

DEMO地址: https://github.com/hugohua/react-native-demo 以后又可以催逼自己会ios开发,哈哈。

过两天再写点经验贴吧。先贴个readme来凑凑字数。

React Native Demo

如何运行

先确保你已安装好了React Native 所需的依赖环境 
在根目录下执行 npm install 
再执行 npm start 
最后在Xcode中点击run 运行 或者按 command + R 
可能遇到的问题

error 1003 错误

在家开着VPN写代码,一般会遇到该问题,解决方法:

打开项目中的AppDelegate.m,找到这行代码: jsCodeLocation = [NSURLURLWithString:@"http://localhost:8081/index.ios.bundle"], ,将localhost换成自己的ip

一点经验

图片自适应

react native 中,图片必须明确写明大小值,不然无法显示,同时width : ‘100%”,这种写法不支持。

如果需要自适应,有几种做法:

只写高度值,不写宽度值,外层容器使用flex来做好布局,再配合resizeMode实现图片自适应即可。

例子1 :

<View style={{flex : 1,borderRightWidth : 1,borderRightColor: '#eeeeee'}}>
                    <Image style={{height: 110,resizeMode: Image.resizeMode.contain}} source={{uri: 'http://gtms01.alicdn.com/tps/i1/TB1nif8HpXXXXc6XVXXAyLxZVXX-320-188.jpg'}} />
                </View>

例子2 :

<View style={{
	  flex: 1,
	  alignItems: 'stretch',
	}}>
	  <Image ssource={{uri: 'http://gtms01.alicdn.com/tps/i1/TB1nif8HpXXXXc6XVXXAyLxZVXX-320-188.jpg'}} style={{ flex: 1 }} />
	</View>

使用Dimensions来获取设备viewport的宽高

var Dimensions = require('Dimensions');
	var { width, height } = Dimensions.get('window');
	var image = (
	  <Image style={{width: width, height: 100 }} source={{uri: 'http://gtms01.alicdn.com/tps/i1/TB1nif8HpXXXXc6XVXXAyLxZVXX-320-188.jpg'}} />
	);

关于layout-css

react-native(rn)中使用flex来布局,目前使用来看,配合positon : ‘absolute’是能够满足基本页面布局需求的。

但是rn中没有zIndex,也没有position : ‘fixed’,在复杂的页面布局中,会稍微有点麻烦,但还是能实现类似的效果。

rg中只实现了css中很小的一个子集,还有很多属性值无法使用,并且属性写法繁琐,如在web中的css 如果要写padding : 10px 5px 15px 20px,在ng中则全部要分开属性写:paddingTop : 10,paddingRight : 5 … 感觉一夜回到解放前。。

positon : ‘absolute’定位方式是相对于父级元素,不管父级是否具有relative。

缺少一些常用的css属性,如中划线,两端对齐等。

最终效果图