react-native的简单使用

前端之家收集整理的这篇文章主要介绍了react-native的简单使用前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

一、网上搜集RNandroid的问题

  • 版本更新太快,到现在还没有到达版本1.0,技术并没有那么稳定
  • 使用了RN,就意味着和Google的android开发控件走上了两条不一样的路线。

二、目前存在的问题

1、react-native库会直接带动整个编译环境提升到最高,否则编译不了。

带来的影响是新的buildtool似乎把很多以前废弃的函数直接undfine了,即可能找不到该函数了。以前的很多业务代码报错,这些都是成本。

2、rn方法数超标的发生

鉴于我们国内app各种sdk的使用,有些比如语音等第三方库的必不可少很容易导致dexIndexOverFlow,虽然这些是有解决方案,但是5.0以下可能导致不适发生。我怀疑RN是方便那些熟悉Web开发的人只需很少的学习成本就可以转入移动应用开发。并未听闻Google对RN的评价,考虑未来andromeda的发布,某些性能会带来变革。对于广大JavaScript出身,想做移动开发而又不想投入人力物力学原生的开发者来说,是个好时机。对于JavaScript出身的开发者,确实是一个拓宽自己职业前进道路的一门新技术,三端(Web,iOS,Android)尽收眼底,单想想就会令人兴奋不已。但是对于原本就是原生出身的开发者,和广大业务型驱动的项目,以及踩坑能力和扛风险能力都比较一般的非一线公司来讲,RN可以关注,可以业余时间来尝试和开拓眼界,其余的,收敛一下激动的小心脏,还是该干啥干啥,保持淡定,真正到了RN初步成熟的时候,再进军也不迟(知乎)

3、 任何以后不知道咋样。

直至当前,任何Java、Objective-C、Swift等官方技术之外,号称新潮的原生解决方案,都有无数个坑,填了一个又来一个,没完没了的。

4、 个人意见

不要作为主语言,可以另开分支单独研发测试。我们项目开始使用RN,填坑无数,RN官方更新太频繁。和原生相比还是有差距。Android官方发布很多版本,RN后续改动也挺大的。需不需要使用RN我觉得主要是考虑到页面变化比较频繁,而又不想通过发布新版本(其实很多第三方渠道审核的时候越来越苛刻了)实现版本的更新才需要使用RN,其实也是可以考虑使用webview,webview相信在Google不停的优化下现在比以前好很多。RN其实有点想从开发中间拦截一次一统江湖的愿景,让大家只需要学习使用RN即可,但我想Google不会坐视不理的,一定会维护自己的地位。
React Native我们也要项目在用。但RN思想和语法的学习曲线有些陡,很多有Web开发经验的人都不一定喜欢。另外很多安卓开发者并没有学习过js,学习React Native成本会比较高。学习React Native最终还是要对原生开发有一定的了解。最后,在一些功能复杂的App,React Native用户体验比不上原生 。

三、运行官网demo

在运行官方第一个demo:AwesomeProject的时候需要修改几个地方:

首先说第一个问题:
需要把AwesomeProject\android\app\build.gradle下的buildToolsVersion修改成已下载的构建版本。当然,如果你已经下载了官方demo默认构建版本的23.0.1,这一步可以忽略不用修改了。
否则可能会出现如下问题:

gradle-wrapper.properties修改成你安装好的就行了。默认的是2.4。
修改好后,可能会出现如下情况

由于网络的原因,下载有可能会很慢,可以使用离线下载的方式。本人使用了astrill,大概两分钟不到就下载好了。
然后运行结果虚拟机显示为:

四、android源生app集成react Native的步骤

1、先按照官方的步骤集成;

1) 在项目的根目录:npm init

生成的package.json需要在scripts处添加
“start”: “node node_modules/react-native/local-cli/cli.js start”

2) 在项目的根目录:npm install –save react react-native

3) Curl –o .flowconfig

https://raw.githubuser content.com/facebook/react-native/master/.flowconfig

4) 在根目录创建index.android.js文件

5) 在android studio项目的build.gradle添加

dependencies {
    ...
    compile "com.facebook.react:react-native:+" // From node_modules.
}

6) 在android studio工程的build.gradle添加

allprojects {
    repositories {
        ...
        maven {
            // All of React Native (JS,Android binaries) is installed from npm
            url "$rootDir/../node_modules/react-native/android"
        }
    }
    ...
}

注意去掉.. ,最后的:url “$rootDir/node_modules/react-native/android”

7) 在android studio项目里添加

<uses-permission android:name="android.permission.INTERNET" />
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />

8) 然后实现官方的MyReactActivity代码

package com.rndemo.reactnativedemo;

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;

import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;

public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler {
    private ReactRootView mReactRootView;
    private ReactInstanceManager mReactInstanceManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mReactRootView = new ReactRootView(this);
        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setBundleAssetName("index.android.bundle")
                .setJSMainModuleName("index.android")
                .addPackage(new MainReactPackage())
                .setUseDeveloperSupport(true)  //BuildConfig.DEBUG
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();
        mReactRootView.startReactApplication(mReactInstanceManager,"HelloWorld",null);
        setContentView(mReactRootView);
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        super.onBackPressed();
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostPause(this);
        }
    }
    @Override
    protected void onResume() {
        super.onResume();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostResume(this,this);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostDestroy(this);
        }
    }

    @Override
    public void onBackPressed() {
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onBackPressed();
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public boolean onKeyUp(int keyCode,KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
            mReactInstanceManager.showDevOptionsDialog();
            return true;
        }
        return super.onKeyUp(keyCode,event);
    }
}

其中配置文件

android:theme="@style/Theme.AppCompat.Light.NoActionBar">

9)最后:

react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/com/your-company-name/app-package-name/src/main/assets/index.android.bundle --assets-dest android/com/your-company-name/app-package-name/src/main/res/

其中 your-company-name在demo中是:

react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output app/src/main/assets/index.android.bundle --assets-dest
dest app/src/main/res/

当然别忘记在main的文件夹下创建assets文件夹,否则会报错:找不到文件夹。

2、遇到的坑,需要修改的地方:

1) 红屏异常:Could not get BatchedBridge,make sure your bundle is packaged correctly

网上有解决方案一或者方案二
如果执行按照上面的命令,在assetes下生成bundle文件,就不需要这样修改了。

2) npm start 和 react-native start(等同react-native run-android)命令

这两个命令都可以启动开发服务器,亲测,但不知道有什么区别。
react-native run-android有时候packager不能自动运行,此时可以手动启动:
react-native start.

五、JSX语法

在 JavaScript 代码里写着 XML 格式的代码称为 JSX,HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法,它允许 HTML 与 JavaScript 的混写。React 官方推荐使用JSX, 当然你想直接使用纯Javascript代码写也是可以的,只是使用JSX,组件的结构和组件之间的关系看上去更加清晰。JSX 类似于 HTML,但不完全一样
http://www.css88.com/react/docs/jsx-in-depth.html

js 代码:
1. //使用JSX
2. React.render(
3. <div>
4. <div>
5. <div>content</div>
6. </div>
7. </div>,8. document.getElementById('example')
9. );
10. 11. //不使用JSX
12. React.render(
13. React.createElement('div',null,14. React.createElement('div',15. React.createElement('div','content')
16. )
17. ),18. document.getElementById('example')19.   );

render 是 React 的最基本方法,用于将模板转为 HTML 语言

六、React

1、react定义

React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件,所有组件类都必须有自己的 render 方法。注意,组件类的第一个字母必须大写,否则会报错。示例:

var HelloMessage = React.createClass({
  render: function() {
    return <h1>
      Hello {this.props.name}
    </h1><p>
      some text
    </p>;
  }
});

上面代码会报错,因为HelloMessage组件包含了两个顶层标签:h1和p。组件的用法与原生的 HTML 标签完全一致,可以任意加入属性,比如 ,就是 HelloMessage 组件加入一个 name 属性,值为 John。组件的属性可以在组件类的 this.props 对象上获取,比如 name 属性就可以通过 this.props.name 读取。
生命周期
当首次使用一个组件类时,会看到如下这些方法依次被调用

getDefaultProps
getInitialState
componentWillMount
render
ComponentDidMount

对于该组件类所有后续应用,将会看到下面的方法依次被调用

getInitialState
componentWillMount
render
componentDidMout

(存在期)随着应用状态的改变,以及组件逐渐受到影响,下面的方法依次被调用

componentwillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate

对于一个组件render是唯一一个必需的方法,并且有特定的规则:
只能通过this.props和this.state访问数据;
可以返回null,false或者任何react组件;
只能出现一个定级组件(不能返回一组);
必需纯净,有位置不能改变组件状态或者修改DOM输出

2、props的解释

this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是 this.props.children 属性。它表示组件的所有子节点。这里需要注意, this.props.children 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。所以,处理 this.props.children 的时候要小心。
React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object。
组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求,此外,getDefaultProps 方法可以用来设置组件属性的默认值。
原生值传递到react native示例:

Bundle bundle = new Bundle();
bundle.putString("key01","value01");
mReactRootView.startReactApplication(mReactInstanceManager,"MyToastAndroid",bundle);

在react native出取值的方法

this.props.key01;

3、虚拟DOM

组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。根据 React 的设计,所有的 DOM 变动,都先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM上,这种算法叫做 DOM diff ,它可以极大提高网页的性能表现。
但是,有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性

4、this.state

组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI。由于 this.props 和 this.state 都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,this.props 表示那些一旦定义,就不再改变的特性,而 this.state 是会随着用户互动而产生变化的特性。
对于复杂的单页面应用,状态(state)管理很重要。
State可能包括:服务端的响应数据、本地对响应数据的缓存、本地创建的数据以及一些UI的状态信息(比如,路由、选中的tab、是否显示下来列表、页码控制等等)。如果state变化不可预测,就会难以调试(state不易重现,很难复现一些bug)和不易扩展(比如优化更新渲染、服务端渲染、路由切换时获取数据等)。
Redux就是用来确保state变化的可预测性,主要的约束有:1)state以单一对象存储在store对象中;2)state只读;3)使用纯函数reducer执行state更新。
store 是一个单一对象:1)管理应用的state;2)通过store.getState()可以获取state;3)通过store.dispatch(action)来触发state更新;4)通过store.subscribe(listener)来注册state来注册state变化监听器;5)通过createStore(reducer,[initialState])创建

5、rn和原生通信

1)Android向JS传递事件

2)AndroidJS被动向Android询问事件消息

示例:
定义:

@ReactMethod
public void callBackTime(String name,Callback callback) {
    callback.invoke("your name");
}

调用

MyToastAndroid.callBackTime("Allure",(msg) => { console.log(msg); ToastAndroid.show(msg,ToastAndroid.SHORT); });

3)promise

React Native的跨语言访问是异步进行的,所以想要给JavaScript返回一个值的唯一办法是使用回调函数或者发送事件。
Promise就是其中一个解决方法
一个Promise对象可以理解为一次将要执行的操作,使用了Promise对象之后可以用一种链式调用的方式来组织代码,让代码更加直观。类似android里的RxAndriod,都是为了使代码美观,链式请求不需要层层嵌套。Promise 对象有三种状态:
1.Fulfilled 可以理解为成功的状态
2.Rejected 可以理解为失败的状态
3.Pending 既不是 Fulfilld 也不是 Rejected 的状态,可以理解为 Promise 对象实例创建时候的初始状态
示例:
定义:

@ReactMethod
public void getPromiseInfo(String name,Promise promise) {
    WritableMap writableMap=new WritableNativeMap();
    writableMap.putString("age","20");
    writableMap.putString("time","2016");
    promise.resolve(writableMap);
}
接收:
MyToastAndroid.getPromiseInfo("Allure").then(msg=> {
            console.log("年龄:" + msg.age + "/n" + "时间:" + msg.time);
            ToastAndroid.show("Promise收到消息:" + "\n" + "年龄:" + msg.age + "时间:" + msg.time,ToastAndroid.SHORT)

            this.setState({
                age: msg.age,time: msg.time,})
        }).catch(error=> {
            console.log(error);
        });

6、自定义原生模块

1)写源生模块类,类似JS里面的Component功能。需要继承ReactContextBaseJavaModule。例如:MyToastModule;

2)写包类,作用是把模块类送到React Native中,实现 ReactPackage。例如:

ToastReactPackage
@Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new MyToastModule(reactContext));
        return modules;
    }

3)需要把这个包类放到需要引入的Activity里面,因为模块类其实可以类比一个控件,最终需要显示出来,相当于布局吧。例如:

mReactRootView = new ReactRootView(this);
        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setBundleAssetName("index.android.bundle")
                .setJSMainModuleName("index.android")
                .addPackage(new MainReactPackage())
                .addPackage(new AnExampleReactPackage())
                .setUseDeveloperSupport(true)  //BuildConfig.DEBUG
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();
        Bundle bundle = new Bundle();
        bundle.putString("key","来自原生代码");
        mReactRootView.startReactApplication(mReactInstanceManager,bundle);
        setContentView(mReactRootView);

4)以上三步骤完成后就可以使用了。例如:

var MyToastAndroid = NativeModules.MyToastAndroid;
    MyToastAndroid.show("sssss",MyToastAndroid.SHORT);

7、路由(route)

使用导航器经常会碰到“路由(route)”的概念。“路由”车厢自现实生活中的路牌,在RN中专指包含了场景信息的对象。renderScene方法是完全根据路由提供的信息来渲染场景的。

七、ES6语法

1、函数参数设置默认值

function log(x,y = 'World') {
  console.log(x,y);
}

2、typeof 运算符

typeof 运算符把类型信息当作字符串返回。typeof 返回值有六种可能: “number,” “string,” “boolean,” “object,” “function,” 和 “undefined.”
typeof 语法中的圆括号是可选项

最后存在的问题

1、在运行别人的代码的时候执行:compile “com.facebook.react:react-native:+”

加载的包始终是react-native-0.20.1.
需要在package.json—> dependencies:react-native里面修改

2、执行:

react-native start
react-natvie run-android
出现如下问题:Android project not found. Maybe run react-native android first?
原因是在原生app里面集成js的命令应该是:
npm start
然后直接运行AS。
或者使用打包命令,生成的bundle到assets目录下,再运行Android studio也行。

3、出现:cant find variable:Component

import React { Component } from ‘react’; 修改为import React,{ Component } from ‘react’;

4、出现的问题Could not connect to development server.

解决办法:红屏引进有提示了。最可能的问题是:adb reverse tcp:8081 tcp:8081

5、Your app does not have the latest code changes because it was restarted manually.Please run from IDE instead.

6、Application XXX has not been registered.This is either due to a require() error during initialization or failure to call AppRegistry.registerComponent.

解决办法:定义的模块名称保存一致:
(1)AppRegistry.registerComponent
(‘MyToastAndroid’,()=> HelloWorld);
2)mReactRootView.startReactApplication(mReactInstanceManager,“MyToastAndroid”,bundle);
setContentView(mReactRootView);
3)@Override
public String getName() {
return “MyToastAndroid”;
}
然后开启服务:react-native start

7、自定义Style的时候就会报错。

解决的办法:首先导入包:StyleSheet
其次自定义的样式需要放在自定义组件Component体外。

8、https://github.com/ldn0x7dc/react-native-media-kit/issues/27

没有解决的问题:

1、 exports的使用

exports.displayName = ‘ButtonExample’;
exports.framework = ‘React’;
exports.title = ‘’;
http://facebook.github.io/react-native/docs/button.html

2、

猜你在找的React相关文章