React Native安裝過程及使用方法

 

中文網站:https://reactnative.cn/docs/getting-started

安裝環境

在Mac平臺上開發React Native需要安裝以下環境和工具:

Note.js
React Native Command Line Tools
XCode/AndroidStudio

1、安裝Node.js

React Native開發需要用到Node.js環境。我們做React Native開發會經常性的和Node.js進行打交道,在Mac上安裝 Node.js可以通過Homebrew,打開終端運行如下命名:

brew install node

安裝完 Node 後建議設置 npm 鏡像以加速後面的過程(如果能翻牆可以省略這步):

npm config set registry https://registry.npm.taobao.org --global
npm config set disturl https://npm.taobao.org/dist --global

2、安裝React Native命令行工具

Note.js安裝成功之後,接下來我們就可以通過npm install來安裝React Native命令行工具了。

打開終端,輸入並執行下面命令即可完成安裝:

npm install -g react-native-cli

3、安裝iOS開發工具XCode/android開發工具android studio

4、安裝一些命令行工具

Watchman則是由 Facebook 提供的監視文件系統變更的工具。安裝此工具可以提高開發時的性能(packager 可以快速捕捉文件的變化從而實現實時刷新)。

brew install watchman

Yarn是 Facebook 提供的替代 npm 的工具,可以加速 node 模塊的下載。React Native 的命令行工具用於執行創建、初始化、更新項目、運行打包服務(packager)等任務。

npm install -g yarn

安裝完 yarn 後同理也要設置鏡像源:

yarn config set registry https://registry.npm.taobao.org --global
yarn config set disturl https://npm.taobao.org/dist --global

安裝 CocoaPods(iOS端依賴),安裝見https://blog.csdn.net/zkdemon/article/details/90241630

5、創建自己第一個react-native項目

使用 React Native 命令行工具來創建一個名爲"TestReactNative"的新項目:

react-native init TestReactNative

自動調用CocoaPods安裝依賴包如果失敗的話,手動到ios目錄下pod install一下(Podfile文件中第一行添加源地址 source 'https://github.com/CocoaPods/Specs.git')

ios和android目錄提前先用xcode和android studio編譯運行一下(android端需要提前在AVD Manager中創建模擬器,創建要求見https://reactnative.cn/docs/getting-started中的介紹)

android端第一次運行的時候app裏面可能會報js錯誤

修改項目目錄/android/app/build.gradle裏

加入

entryFile: "index.js",
bundleAssetName: "index.android.bundle",
bundleInDebug: true,
bundleInRelease: true

這幾句重新運行就沒問題了。

後邊就直接可以在項目目錄中運行以下命令就可以編譯運行:

cd TestReactNative
// 運行IOS
yarn ios
// 運行android(提前需要把模擬器開開,在運行命令)
yarn android

編譯成功可以看到一個簡單的demo:

 

組件component

1、組件創建方式

常用的組件創建方式有兩種,第一種是單純一個JavaScript函數,第二種是創建一個JS類

 

    import React, {Component} from 'react';
    import { Text, View } from 'react-native';

    // 方式一:
    const MyComponent = (props) => (
        <View>
            <Text>MyComponent</Text>
        </View>
    );

    // 方式二:
    class MyClass extends Component {
      render() {
          return (
              <View>
                  <Text>MyClass</Text>
              </View>
          );
      }
    }

    export { MyClass };

    export default MyComponent;

以上兩種方式創建的組件用法完全一樣,區別在於方式一無法複寫組件的聲明週期,無法維護state,關於聲明週期與state我們將在以後章節裏面講解。

2、組件和模塊的導出和引入

1)export 命令

一個獨立的文件就是一個模塊。該文件內部的所有變量,外部無法獲取。如果你希望外部能夠讀取模塊內部的某個變量,就必須使用export關鍵字輸出該變量。下面是一個 JS 文件,裏面使用export命令輸出變量。如上方的自定義組件中的

 

export { MyClass };

export default MyComponent;
  • export defalt命令在每個文件中只能存在一個,顧名思義是導出組件的默認輸出。

  • 接下來介紹export的幾種寫法

    // 方式一:分別導出三個變量
    export const firstName = 'Michael';
    export const lastName = 'Jackson';
    export const year = 1958;
    
    // 方式二:用大括號統一導出(和方式一效果一樣)
    const firstName = 'Michael';
    const lastName = 'Jackson';
    const year = 1958;
    
    export { firstName, lastName, year };
    
    // 除了導出變量,還可以導出方法和類
    export function logExport() {
      console.log('export');
    }
    
    class MyClass extends Component {
      render() {
          return (
              <View>
                  <Text>MyClass</Text>
              </View>
          );
      }
    }
    export default MyClass;
    
    // 使用as關鍵字給輸出重新命名
    export { firName as firstName };
    

2)import 命令

使用export命令定義了模塊的對外接口以後,其他 JS 文件就可以通過import命令加載這個模塊。

 

    // 非export default輸出的,需要使用大括號
    // 和export相同也可以使用as 取別名
    import { firstName, MyComponent ,year as yearName } from './MyComponent';

    // 使用export default時,對應的import語句不需要使用大括號
    import MyClass from './MyComponent';

    // 本質上,export default就是輸出一個叫做default的變量或方法,然後系統允許你爲它取任意名字。所以,下面的寫法是有效的。
    import OtherName from './MyComponent';

通過 export 和import 我們就可以在app.js中使用自己創建的組件了

 

    ...

    import OtherName from './MyComponent';
    ...

    export default class App extends Component<Props> {

        render() {

            return (

              <View style={styles.container}>

                <Text style={styles.welcome}>Welcome to React Native!</Text>

                <Text style={styles.instructions}>To get started, edit App.js</Text>

                <Text style={styles.instructions}>{instructions}</Text>

                <OtherName />

              </View>
           );
        }
    }

組件生命週期

生命週期

如圖,可以把組件生命週期大致分爲三個階段:

  • 第一階段:是組件第一次繪製階段,如圖中的上面虛線框內,在這裏完成了組件的加載和初始化,其中getDefaultProps,getInitialState 在新版的Component中ES6語法繼承時,直接複寫方法會報異常,RN API要求我們props,state的初始化在Component的constructor函數中完成;

  • 第二階段:是組件在運行和交互階段,如圖中左下角虛線框,這個階段組件可以處理用戶交互,或者接收事件更新界面;

  • 第三階段:是組件卸載消亡的階段,如圖中右下角的虛線框中,這裏做一些組件的清理工作。

進入一個RN界面時,Component的聲明週期函數大致流程如下:

  • 1.constructor構造函數,從上一個界面傳過來的數據props在作爲constructor的參數,在constructor中做一些初始化的操作,如props,state等初始化;函數原型:void constructor(props)

  • 2.componentWillMount,第一次繪製組件(render)前觸發該生命週期函數;函數原型:void componentWillMount()

  • 3.render繪製組件到界面上;函數原型:void render()

  • 4.componentDidMount,第一次揮之組件(render)後觸發該生命週期函數,觸發該函數說明RN組件繪製已經完成了,虛擬DOM已經構建完成;從這個函數開始我們就可以和JS其他框架開始交互了,例如定時器,網絡請求等操作。函數原型:void componentDidMount()

  • 5.componentWillReceiveProps,當組件收到新的屬性時,觸發該函數。函數原型:void componentWillReceiveProps( object nextProps )

  • 6.shouldComponentUpdate,當組件屬性(props)或者狀態(state)發生變化時,都會觸發該函數。函數原型:boolean shouldComponentUpdate( object nextProps, object nextState ); 若函數返回true,則繼續觸發componentWillUpdate,render,componentDidUpdate等方法;若函數返回false,則不做任何處理;默認情況下,這個函數永遠返回true用來保證數據變化的時候 UI 能夠同步更新。在大型項目中,你可以自己重載這個函數,通過檢查變化前後屬性和狀態,來決定 UI 是否需要更新,能有效提高應用性能。

  • 7.componentWillUpdate,如果組件狀態或者屬性改變,並且上面的shouldComponentUpdate(object nextProps, object nextState)返回爲true,則觸發該方法,函數原型:void componentWillUpdate(object nextProps, object nextState),函數中參數實際上與shouldComponentUpdate中的參數一樣,是同一個數據源;需要特別注意的是,在這個函數裏面,你就不能使用this.setState來修改狀態,否則會循環調用該函數導致堆棧溢出。這個函數調用之後,就會把nextProps和nextState分別設置到this.props和this.state中。緊接着這個函數,就會調用render()來更新界面了。

  • 8.componentDidUpdate,更新render結束後,則調用該方法,函數原型:void componentDidUpdate(object prevProps, object prevState);因爲到這裏已經完成了屬性和狀態的更新了,此函數的輸入參數變成了prevProps和prevState。

  • 9.componentWillUnmount,當組件要被從界面上移除的時候,就會調用componentWillUnmount(),函數原型:void componentWillUnmount();在這個函數中,可以做一些組件相關的清理工作,例如取消計時器、網絡請求等。

插件

(1)React Navigation 4.x

官網文檔https://reactnavigation.org/docs/getting-started/

4.x 版本從 react-navigation 中移除了各類導航器,同時還依賴了一些其他的包需要手動安裝

npm install react-navigation react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context
npm install react-navigation-stack @react-native-community/masked-view react-navigation-tabs

reactnative 0.60 版本之後,安裝完成之後會自動 link。

Android 端需要手動進行一些修改,編輯 android/app/build.gradle,在 dependencies 中添加如下內容:

implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha02'

編輯 Android 中的 MainActivity.java,添加如下內容:

package com.reactnavigation.example;

import com.facebook.react.ReactActivity;

import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;

public class MainActivity extends ReactActivity {

  @Override
  protected String getMainComponentName() {
    return "Example";
  }

  @Override
  protected ReactActivityDelegate createReactActivityDelegate() {
    return new ReactActivityDelegate(this, getMainComponentName()) {
      @Override
      protected ReactRootView createRootView() {
        return new RNGestureHandlerEnabledRootView(MainActivity.this);
      }
    };
  }
}

iOS端需要進入項目的ios目錄執行:

pod install

使用時界面下邊如果經常報js警告:

Calling getNode() on the ref of an Animated component is no longer necessary. You can now directly use the ref instead. This method will be removed in a future release.

找到項目node_modules/react-native-safe-area-view/index.js,修改192行

把this.view.getNode().measureInWindow((winX, winY, winWidth, winHeight)改爲this.view.measureInWindow((winX, winY, winWidth, winHeight),警告就消失了。

創建tabbar及導航

import React from 'react';
import {View,Text,Image,Button} from 'react-native';
import {createAppContainer} from 'react-navigation';
import {createBottomTabNavigator} from 'react-navigation-tabs';
import {createStackNavigator} from 'react-navigation-stack';

import App1 from './App1';
import App2 from './App2';
import Introd from './Introd';

class nav1 extends React.Component {
    render() {
        return (
            <View>
                <Text>this is nav1</Text>
                <Button 
                    title={'點擊前往Introd'}
                    onPress={() => {
                        this.props.navigation.push('歡迎頁')
                    }}
                />
            </View>
        )
    }
}

const chiStack = createStackNavigator({
    "次頁": {
      screen: App2,
    },
    "歡迎頁": {
      screen: Introd,
    },
  },
  {
    initialRouteName: "次頁",
});

const qStack = createStackNavigator({
    "導航": {
      screen: nav1,
    },
    "歡迎頁": {
      screen: Introd,
    },
  },
  {
    initialRouteName: "導航",
});

const TabNavigator = createBottomTabNavigator(
  {
    "App1":{
      screen: App1,
      navigationOptions: {
          title: "首頁",
          tabBarIcon:({ focused, horizontal, tintColor })=>{
              return <Image source={require('./img/1.png')} style={{width: 10, height: 10}}/>
          }
      }
    },
    "App2":{
      screen: chiStack,
      navigationOptions: {
          title: "次頁",
          tabBarIcon:({ focused, horizontal, tintColor })=>{
              return <Image source={require('./img/2.png')} style={{width: 10, height: 10}}/>
          }
      }
    },
    "導航":{
      screen: qStack
    }
  },
  {
    tabBarOptions: {
      showIcon: false,
      activeTintColor: 'black',
      inactiveTintColor: 'gray',
      labelStyle: {
        fontSize: 12,            
      },
      style: { 
        backgroundColor: 'white', 
      }
    }
  }
);

export default createAppContainer(TabNavigator);

React Navigation 5.x

npm install @react-navigation/native

npm install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view

npm install @react-navigation/stack

npm install @react-navigation/bottom-tabs

iOS端需要進入項目的ios目錄執行:

pod install

 創建tabbar及導航

import 'react-native-gesture-handler';
import React,{Component} from 'react';
import {View,Text,Image,Button,SafeAreaView} from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

import App1 from './App1';
import App2 from './App2';
import Introd from './Introd';
import {
  Cat,
  Bananas,
} from './utils';

class nav1 extends React.Component {
    render() {
        return (
          <SafeAreaView>
            <View>
                <Text>this is nav1</Text>
                <Button 
                    title={'點擊前往Introd'}
                    onPress={() => {
                        this.props.navigation.navigate('歡迎頁')
                    }}
                />
            </View>
            <Bananas name="App"/>
          </SafeAreaView>
        )
    }
}

const navStack = createStackNavigator();
export class navStackScreen extends Component {
  render() {
    return (
      <navStack.Navigator>
        <navStack.Screen name="導航頁s" component={nav1} />
        <navStack.Screen name="歡迎頁" component={Introd} />
      </navStack.Navigator>
    );
  }
}

const ciStack = createStackNavigator();
export class ciStackScreen extends Component {
  render() {
    return (
      <ciStack.Navigator>
        <ciStack.Screen name="次頁" component={App2} />
        <ciStack.Screen name="歡迎頁1" component={Introd} />
      </ciStack.Navigator>
    );
  }
}

const Tab = createBottomTabNavigator();
export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator
        screenOptions={({ route }) => ({
          tabBarIcon: ({ focused, color, size }) => {
            if (route.name === '次頁') {
              return <Image source={require('./img/1.png')} style={{width: 25, height: 25}}/>;
            } else  {
              return <Image source={require('./img/2.png')} style={{width: 25, height: 25}}/>;
            }
          },
        })}
        tabBarOptions={{
          activeTintColor: 'tomato',
          inactiveTintColor: 'gray',
        }}
      >
        <Tab.Screen name="首頁" component={App1} />
        <Tab.Screen name="次頁" component={ciStackScreen} />
        <Tab.Screen name="導航頁" component={navStackScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}


在沒有導航器的情況下進行導航:https://reactnavigation.org/docs/navigating-without-navigation-prop/ 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章