RN学习

220 阅读5分钟

基本环境搭建

Node>14 JDK11 低于0.67的需要1.8 Android Studio

JDK安装:

下载jdk11并安装。然后修改环境变量

jdk11网盘分享:链接:pan.baidu.com/s/1W9NDfju9… 提取码:abcd

image.png

看到下面就表示安装成功

image.png

Android Studio安装

下载地址: developer.android.com/studio/inde…

配置环境变量时,若不知道SDK安装的位置,可在andrid studio的 Appearance & Behavior → System Settings → Android SDK下看sdk的位置

image.png

按照react native官网进行安装即可

初始化项目

npx react-native init rnproject

cd rnproject

运行项目:

android:yarn android

ios:

  • cd ios && pod install && cd ../
  • yarn ios

第一次运行时,需要下载大量的编译依赖,耗时可能非常的长。 注:下载的依赖会很慢,可以改一下build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    ext {
        buildToolsVersion = "33.0.0"
        minSdkVersion = 21
        compileSdkVersion = 33
        targetSdkVersion = 33

        // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
        ndkVersion = "23.1.7779620"
    }
    repositories {
        maven{ url 'https://maven.aliyun.com/repository/google'}
        google()
        mavenCentral()
    }
    dependencies {
        classpath("com.android.tools.build:gradle:7.3.1")
        classpath("com.facebook.react:react-native-gradle-plugin")
    }
}
allprojects {
    repositories {
        maven{ url 'https://maven.aliyun.com/repository/google'}
        google()
        jcenter()
    }
}

VsCode 插件:ES7 React/Redux/GraphQL/React-Native 模拟器运行 ctrl+m 可调试

响应式布局

  • Flexbox
  • Dimensions
import { Dimensions } from 'react-native
const windowWidth = Dimensions.get('window').width
const windowHeigth = Dimensions.get('window').height

基础组件学习

AsyncStorage 本地存储

@react-native-async-storage/async-storage

Geolocation 获取地理信息

@react-native-community/geolocation

yarn add @react-native-community/geolocation

需要配置权限

使用示例;

Geolocation.getCurrentPosition(
     info => {
          console.log(info)
      },
      error => Alert.alert('报错', JSON.stringify(error)),
      {
          timeout: 20000
       }
 );

Camera 相机

react-native-vision-camera

Android

npm i react-native-vision-camera
// 1.android/app/src/main/AndroidManifest.xml添加权限
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>


// 2. `android/settings.gradle`里加入下面的
include ':react-native-camera'
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
// 3 android/app/build.gradle文件的dependencies 里面
implementation project(':react-native-camera')

android { 
... 
defaultConfig { 
... 
missingDimensionStrategy 'react-native-camera', 'general' 
// <--- insert this line } 
}

image.png

image.png

image.png 使用示例:

import { RNCamera } from 'react-native-camera'

<RNCamera
          ref={ref => {
            this.camera = ref;
          }}
          style={styles.preview}
          type={RNCamera.Constants.Type.back} // 摄像头的方向,back 后,front 前
          flashMode={RNCamera.Constants.FlashMode.on} // 相机的闪光模式
          androidCameraPermissionOptions={{
            title: 'Permission to use camera',
            message: 'We need your permission to use your camera',
            buttonPositive: 'Ok',
            buttonNegative: 'Cancel',
          }}
          androidRecordAudioPermissionOptions={{
            title: 'Permission to use audio recording',
            message: 'We need your permission to use your audio',
            buttonPositive: 'Ok',
            buttonNegative: 'Cancel',
          }}
          onGoogleVisionBarcodesDetected={({ barcodes }) => {
            console.log(barcodes);
          }}
        />
        <View style={{ flex: 0, flexDirection: 'row', justifyContent: 'center' }}>
          <TouchableOpacity onPress={this.takePicture} style={styles.capture}>
            <Text style={{ fontSize: 14 }}> 拍照 </Text>
          </TouchableOpacity>
        </View>
        
        takePicture = async () => {
    if (this.camera) {
      const options = { quality: 0.5, base64: true };
      const data = await this.camera.takePictureAsync(options);
      Alert.alert('图片地址', data.uri);
    }
  };

使用相机时会报如下的错误 ViewPropTypes will be removed from React Native, along with all other PropTypes. We recommend that you migrate away from PropTypes and switch to a type system like TypeScript. If you need to continue using ViewPropTypes, migrate to the 'deprecated-react-native-prop-types' package.

也就是ViewPropTypes在新版的react-native已经被移除了。

ImagePicker 调用摄像头 访问相册

react-native-image-picker

yarn add react-native-image-picker

矢量图标库

react-native-vector-icons

npm i --save-dev @types/react-native-vector-icons
npm install --save react-native-vector-icons

需要配置 Android:

// android/app/build.gradle
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"

ios:

image.png

路由和导航

reactnavigation.org/

基础依赖

yarn add @react-navigation/native
yarn add react-native-screens react-native-safe-area-context

// 链接
// 安卓下不需要任何操作
// ios下需要手动链接路由 npx pod-install ios

// 导航的跳转
naigation.navigate('routeName')// 将当前路由放入路由栈中,如果之前有,将跳转到这个路由
navigation.push('routeName')
navigation.goBack()
navigation.popToTop()

使用react-native-screens 需要在androis/app/src/main/java/com/*/MainActivity.java中加入以下代码

image.png

native-stack导航

RN中没有history对象 在跳转之前,先将路由声明在Stack中

yarn add @react-navigation/native-stack

<Stack.Navigator initialRouteName={'Splash'}>
   <Stack.Screen
     name="Splash"
     component={SplashScreen}
     options={{headerShown: false}}
    />
    <Stack.Screen
      name="Login"
      component={LoginScreen}
      options={{headerShown: false}}
    />
  </Stack.Navigator>

BottomTab 底部导航

yarn add @react-navigation/bottom-tabs

import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
const Tab = createBottomTabNavigator();
<Tab.Navigator
      initialRouteName="News"
      screenOptions={({route}) => ({
        tabBarIcon: ({focused, color, size}) => {
          let iconName: string = '';

          if (route.name === 'Home') {
            iconName = focused ? 'add-circle' : 'add-circle-outline';
          } else if (route.name === 'News') {
            iconName = focused ? 'settings' : 'settings-outline';
          } else if (route.name === 'User') {
            iconName = focused ? 'person' : 'person-outline';
          }
          return <Ionicons name={iconName} size={size} color={color} />;
        },
        tabBarActiveTintColor: 'tomato',
        tabBarInactiveTintColor: 'grey',
      })}>
      <Tab.Screen
        name="Home"
        component={HomeScreen}
        options={{headerShown: false}}
      />
      <Tab.Screen
        name="News"
        component={NewsScreen}
        options={{headerShown: false}}
      />
      <Tab.Screen name="User" component={UserScreen} />
    </Tab.Navigator>

image.png

Drawer 抽屉导航

npm install @react-navigation/drawer

image.png

MaterialTopTab 滑动切换的tab

yarn add @react-navigation/material-top-tabs react-native-tab-view

image.png

Nesting navigators 嵌套导航

image.png

路由传参

navigation.naigate('路由名称', {key: 'value'})
类组件接收: this.props.route.params.key
函数组件接收: route.params.key

项目内容

1.增加git钩子,提交前验证代码格式

  • husky: 被用来添加一些 git 钩子,这里我们需要一个用 pre-commit 在每次 git commit 操作时执行 lint-staged 命令。

  • lint-staged: 可以对 git 暂存区文件(也就是你想要 commit 的文件)执行一些操作,这样做即提高了性能又提高了效率。

yarn add -D husky lint-staged
npm set-script prepare "husky install"
npm run prepare //手动husky install
// 以上两条会自动生成.husky文件

// 配置文件 package.json
script: {
...
"precommit": "lint-staged"
},
"lint-staged": {
    "src/**/**/*.{js,ts,tsx}": [
      "prettier --write",
      "eslint"
    ]
  },

// 创建git hook
npx husky add .husky/pre-commit "npm run precommit"

增加commit提交规范

npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

// .husky/commit-msg
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx --no-install commitlint --edit $1
// 安装验证提交信息脚本
npm i @commitlint/config-conventional @commitlint/cli -D
// 新增commitlint.config.js
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    // eslint-disable-next-line prettier/prettier
        'type-enum': [2, 'always',
      [
        'build',
        'ci',
        'chore',
        'docs',
        'feat',
        'fix',
        'perf',
        'refactor',
        'revert',
        'style',
        'test',
        'merge',
      ],
    ],
    // 'subject-full-stop': [0, 'never'],
    // 'subject-case': [0, 'never']
  },
};
//   build:主要目的是修改项目构建系统(例如 glup,webpack,rollup 的配置等)的提交
//   ci:主要目的是修改项目继续集成流程(例如 Travis,Jenkins,GitLab CI,Circle等)的提交
//   docs:文档更新
//   feat:新增功能
//   fix:bug 修复
//   perf:性能优化
//   refactor:重构代码(既没有新增功能,也没有修复 bug)
//   style:不影响程序逻辑的代码修改(修改空白字符,补全缺失的分号等)
//   test:新增测试用例或是更新现有测试
//   revert:回滚某个更早之前的提交
//   chore:不属于以上类型的其他类型

2.增加redux

yarn add redux react-redux redux-thunk @reduxjs/toolkit
// 创建redux目录,创建根store.ts文件
import {createStore, applyMiddleware} from 'redux';
import reducers from './reducers/index';
import reduxThunk from 'redux-thunk';

const store = createStore(reducers, applyMiddleware(reduxThunk));
export default store;

// reducers/index
import {combineReducers} from 'redux';

import User from './User';

export default combineReducers({
  User,
});

// .User
import actionTypes from '../actions/actionType';

const initState = {
  isLogin: false,
};

export default (
  state = initState,
  action: {type: string; payload: Function},
) => {
  switch (action.type) {
    case actionTypes.LOGIN_SUCCESS:
      return {
        ...state,
        ...action.payload,
        isLogin: true,
      };
    case actionTypes.LOGIN_FAILED:
      return {
        isLogin: false,
      };
    default:
      return state;
  }
};

// actions/actionType
// 定义reducers中的action。type的值
export default {
  LOGIN_SUCCESS: 'LOGIN_SUCCESS',
  LOGIN_FAILED: 'LOGIN_FAILED',
};

// actions/User.ts
import actionTypes from './actionType';

// 登录成功
export const loginSuccess = (userInfo: any) => {
  return {
    type: actionTypes.LOGIN_SUCCESS,
    payload: userInfo,
  };
};

// 登录失败
export const loginFailed = () => {
  return {
    type: actionTypes.LOGIN_FAILED,
  };
};

// 退出
export const logout = () => (dispatch: (arg0: {type: string}) => void) => {
  dispatch(loginFailed());
};


image.png

3.配置app.tsx

// 加载导航依赖
npm install @react-navigation/native @react-navigation/native-stack @react-navigation/stack

// app.tsx
import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {Provider as StoreProvider} from 'react-redux';
import store from './src/redux/store';
// 入口文件,配置主导航以及未不需要登录时的其他导航
import Index from './src/page/navigation/index';

function App(): JSX.Element {
  return (
    <StoreProvider store={store}>
      <NavigationContainer>
        <Index />
      </NavigationContainer>
    </StoreProvider>
  );
}

export default App;

4.代码仓库

gitee.com/olhong/rn-p…

还将不断的继续完善