React Native 入门踩坑
开发环境搭建及环境变量配置
开发rn第一步需要配置安卓环境
android studio下载地址: https://developer.android.google.cn/studio/archive
参考官方文档 使用科学的上网方式配置即可
官网参考地址: https://www.react-native.cn/docs/environment-setup
我的环境 macos+ 安卓;
初始化项目
npx react-native init ProjectName
cd 项目文件
yarn install
运行官方demo
项目初始化完成 我们先来跑起来;
选用网易mumu模拟器来运行;
参考地址: https://blog.csdn.net/S3328047358/article/details/119324911
配置好 网易mumu
npm run start // 启动服务 开发调试期间不要关闭 一般运行在8081 可使用127.0.0.1:8081访问查看
npm run android // 随后可以看到 demo被打包运行在模拟器上
// 开发工程有问题 不能解决 尝试重新运行
## 调试: 标签结构,控制台,网络请求
方式一: 谷歌浏览器 查看控制台及网络请求
点击 摇一摇 一次不行 多点几次, 会弹出开发者菜单
点击 Debug 会自动打开localhost: 8081
打开控制台 查看输出
网络请求需要添加代码才能查看
找到项目的入口文件 index.js
, 加入以下代码即可
GLOBAL.XMLHttpRequest = GLOBAL.originalXMLHttpRequest || GLOBAL.XMLHttpRequest
方式二: 推荐使用 react-native-debugger 三方面都可调试
下载软件: https://github.com/jhen0409/react-native-debugger
先启动软件;
在到模拟器中启动 开发者菜单 点击debug
这样模拟器和调试器就会链接在一起啦
标签结构便捷查看参考官方文档:
https://www.react-native.cn/docs/debugging#integration-with-react-native-inspector
控制台直接看即可
网络请求需要修改配置看:
菜单栏Debugger => openConfig file => defaultNetworkInspect 改成 true
方式三: 真机调试
参考: https://www.react-native.cn/docs/running-on-device
修改目录结构
配置路由
使用官方推荐的 react-navigation: https://reactnavigation.org/docs/stack-navigator/
安装
npm install @react-navigation/native
npm install @react-navigation/native-stack
路由依赖
npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context
react-navigation路由思路和react-router的思路是相同的 都是组件化的路由, 路由配置在哪里 只要和地址匹配就会被渲染;
### 路由基本使用:
// App.js 文件
import React from 'react';
import { View } from 'react-native';
import Nav from './src/routers/nav';class App extends React.Component {constructor(props) {super(props)}render(){return (<View style={{flex: 1}}><Nav></Nav></View>)}
}export default App;
// /src/routers/nav.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
// 导入导航容器
import { createNativeStackNavigator } from '@react-navigation/native-stack';
// 导入创建堆栈导航方法
import Login from '../pages/login';
import Home from '../pages/home';
//创建导航
const Stack = createNativeStackNavigator();class Nav extends React.Component {render(){return (<NavigationContainer>{/* initialRouteName 初始默认路由 可用字段动态渲染 如不设置默认路由, 则会自动匹配第一个路由页面*/}{/* screenOptions 设置所有导航栏默认样式 */}<Stack.Navigator initialRouteName='login' screenOptions={{headerStyle: {backgroundColor: '#f4511e',},headerTintColor: '#fff',headerTitleStyle: {fontWeight: 'bold',},}}><Stack.Screen name="login" component={Login} />{/* options 设置顶部页面标题及样式 */}<Stack.Screen name="home" component={Home} options={{headerShown: false, //是否显示标题title: '首页',headerStyle: {backgroundColor: '#f4511e',},headerTintColor: '#fff',headerTitleStyle: {fontWeight: 'bold',}}}/></Stack.Navigator></NavigationContainer>)}
}export default Nav
// /src/pages/home/index.js 路由跳转及传参import React from 'react';
import { View, Text, Button } from 'react-native';class Home extends React.Component {constructor(props){super(props)console.log('home页面');}toLoginWidthParams = () => {this.props.navigation.push('login', {con: '传递参数',id: '123'});// navigation.push('Details') 切换页面// navigation.replace('Details') 替换页面// navigation.goBack() 返回// navigation.popToTop() 回到最顶层页面}toLogin = () => {console.log('去登录页面');this.props.navigation.navigate('login');}render() {return (<View style={{flex: 1}}><View style={{color: 'red',fontSize: 14, flex: 1}}><Text>首页内容</Text><Button title="去登录页面1" onPress={this.toLogin}></Button><Button title="带参数去登录页面" onPress={this.toLoginWidthParams}></Button></View></View>)}
}export default Home;
// /src/pages/login/index.js 路由参数接受import React from 'react';
import { View, Text, Button } from 'react-native';class Login extends React.Component {constructor(props){super(props)}componentDidMount() {let params = this.props.route.params; //接收参数console.log('login componentDidMount', params);}toHome = () => {this.props.navigation.push('home');}render() {return (<View style={{flex: 1}}><View style={{color: 'red',fontSize: 14, flex: 1}}><Text>这是login页面</Text><Button title='去首页' onPress={this.toHome}></Button></View></View>)}
}export default Login;
嵌套及tabbar路由
npm install @react-navigation/bottom-tabs
参考地址: https://reactnavigation.org/docs/tab-based-navigation
https://reactnavigation.org/docs/nesting-navigators
// /src/routers/nav.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
// 导入导航容器
import { createNativeStackNavigator } from '@react-navigation/native-stack';
// 导入创建堆栈导航方法
import Login from '../pages/login';
import TabBar from '../pages/tabBar'
//创建导航
const Stack = createNativeStackNavigator();class Nav extends React.Component {render(){return (<NavigationContainer><Stack.Navigator initialRouteName='tabBar'><Stack.Screen name="tabBar" component={TabBar} options={{headerShown: false}}/><Stack.Screen name="login" component={Login} /></Stack.Navigator></NavigationContainer>)}
}export default Nav;
// /src/pages/tabbar/index.js
import React from 'react';
import { View, Text } from 'react-native';
// 官方推荐库
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';import Home from '../home';
import Articles from '../articles';
//创建导航
const Tab = createBottomTabNavigator();class TabBar extends React.Component {constructor(props) {super(props)}render(){return (<View style={{flex: 1}}><View style={{flex: 1}}><Tab.Navigator initialRouteName='home' screenOptions={({ route }) => ({tabBarIcon: ({ focused, size }) => {// 可以返回任何组件内容, 但一般是图标let color = focused ? 'red' : 'gray';return <Text style={{ fontFamily: "iconfont", color, fontSize: 30 }} >图标</Text>;},})}tabBarOptions={{activeTintColor: 'red',inactiveTintColor: 'gray',}}>{/* options 设置顶部页面标题及样式 */}<Tab.Screen name="home" component={Home} options={{headerShown: false,tabBarBadge: 3,}}/><Tab.Screen name="articles" component={Articles} options={{headerShown: false}}/></Tab.Navigator></View></View>)}
}export default TabBar;
// /src/pages/home/index.js
import React from 'react';
import { View, Text, Button } from 'react-native';class Home extends React.Component {constructor(props){super(props)console.log('home页面');}toLoginWidthParams = () => {this.props.navigation.push('login', {con: '传递参数',id: '123'});}toLogin = () => {console.log('去登录页面');this.props.navigation.navigate('login');}render() {return (<View style={{flex: 1}}><View style={{color: 'red',fontSize: 14, flex: 1}}><Text>首页内容</Text><Button title="去登录页面1" onPress={this.toLogin}></Button><Button title="带参数去登录页面" onPress={this.toLoginWidthParams}></Button></View></View>)}
}export default Home;
// /src/pages/articles/index.js
import React from 'react';
import { View, Text, Button } from 'react-native';class Articles extends React.Component {constructor(props){super(props)console.log('Articles组件');}componentDidMount() {let params = this.props.route.params; //接收参数console.log('componentDidMount', params);}goHome = () => {// this.props.navigation.push('home');// 本页面跳转 home 页 需要用这个方法; push方法在嵌套路由无效果this.props.navigation.navigate('home');}render() {return (<View style={{flex: 1}}><View style={{color: 'red',fontSize: 14, flex: 1}}><Text>这是Articles页面</Text><Button title="去首页" onPress={this.goHome}></Button></View></View>)}
}
export default Articles;
// /src/pages/login/index.js
import React from 'react';
import { View, Text, Button } from 'react-native';class Login extends React.Component {constructor(props){super(props)}componentDidMount() {let params = this.props.route.params; //接收参数console.log('login componentDidMount', params);}goArticle = () => {// 嵌套路由导航切换 使用此方法 不带参数this.props.navigation.navigate('articles');// 带参数跳转方式// this.props.navigation.navigate('tabBar', { screen: 'articles', params: { con: '传递参数', id: '123' }});}render() {return (<View style={{flex: 1}}><View style={{color: 'red',fontSize: 14, flex: 1}}><Text>这是login页面</Text><Button title='去文章页面' onPress={this.goArticle}></Button></View></View>)}
}export default Login;
*** 路由方面遗留一个问题: rn的路由能否像react-router使用高阶组件实现路由守卫?
暂时未找到解决办法, 只能根据实际的操作 在进行判断.
项目中引入iconfont
在字体图标网站上下载 字体
然后拷贝 ttf后缀的文件到
android\app\src\main\assets\fonts
中 如果没有assets
文件夹可以新建一个然后 给
Text
标签 设置<Text style={{ fontFamily: "iconfont", color: "red" }} >{'\ue82b'}</Text>
然后记得重启项目
数据共享
父子组件传值,兄弟组件传值,与react中一样
参考: https://blog.csdn.net/S3328047358/article/details/118355972
### 无关系组件传值-Mobx简单入门
react中使用redux ,在rn中官方推荐使用mobx上手难度小于redux
中文文档: https://cn.mobx.js.org/
其他参考文档: https://blog.csdn.net/xiapi3/article/details/106901684/
https://blog.csdn.net/zjscy666/article/details/107905684
安装依赖
mobx
核心库mobx-react
方便在react中使用mobx技术的库@babel/plugin-proposal-decorators
让rn
项目支持es7
的装饰器语法的库
yarn add mobx mobx-react @babel/plugin-proposal-decorators
在
babel.config.js
添加以下配置plugins: [['@babel/plugin-proposal-decorators', { 'legacy': true }]]
/src/mobx.index.js
import { observable, action, makeObservable, computed } from "mobx";class RootStore {constructor(){// 最新版本的mobx 都要加这个 不然会获取不到修改后的值makeObservable(this)}// observable 表示数据可监控 表示是全局数据@observable name = "hello123";// action行为 表示 changeName是个可以修改全局共享数据的方法@action changeName(name) {this.name = name;}// 使用方法和name一样直接get即可@computed get total() {let newName = this.name + '最新的name值';return newName;} } export default new RootStore();
App.js
import React from 'react'; import { View } from 'react-native'; import Nav from './src/routers/nav'; // 引入store import rootStore from "./src/mobx"; // 使用Provider使得所有组件都可访问store import { Provider} from "mobx-react";class App extends React.Component {constructor(props) {super(props)}render(){return (<View style={{flex: 1}}><Provider rootStore={rootStore}><Nav></Nav></Provider></View>)} } export default App;
/src/pages/home/index.js
import React from 'react'; import { View, Text, Button } from 'react-native'; import {inject,observer } from "mobx-react";@inject("rootStore") // 注入 用来获取 全局数据的 @observer // 当全局发生改变了 组件的重新渲染 从而显示最新的数据 class Home extends React.Component {constructor(props){super(props)console.log('home组件 this.props.rootStore.name', this.props.rootStore.name);}toLogin = () => {this.props.navigation.navigate('login');}toChangeName = () => {console.log('toChangeName');this.props.rootStore.changeName(Date.now())}render() {return (<View style={{flex: 1}}><View style={{color: 'red',fontSize: 14, flex: 1}}><Text>这是home页面rootStore的name---{this.props.rootStore.name}</Text><Text>rootStore:get total---{this.props.rootStore.total}</Text><Button title="去登录页面" onPress={this.toLogin}></Button><Button title="修改store-name" onPress={this.toChangeName}></Button></View></View>)} }export default Home;
/src/pages/articles/index.js
import React from 'react'; import { View, Text, Button } from 'react-native'; import {inject,observer } from "mobx-react";@inject("rootStore") // 注入 用来获取 全局数据的 @observer // 当全局发生改变了 组件的重新渲染 从而显示最新的数据 class Articles extends React.Component {constructor(props){super(props)console.log('Articles组件');}componentDidMount() {let params = this.props.route.params; //接收参数console.log('componentDidMount', params);}goHome = () => {this.props.navigation.navigate('home');}render() {return (<View style={{flex: 1}}><View style={{color: 'red',fontSize: 14, flex: 1}}><Text>这是Articles页面</Text><Text>rootStore: name---{this.props.rootStore.name}</Text><Text>rootStore:get total---{this.props.rootStore.total}</Text><Button title="去首页" onPress={this.goHome}></Button></View></View>)} } export default Articles;
Mobx模块化使用
目录划分:
截图6
/src/mobx/index.js
import NumberStore from "./modules/number"; import UserStore from './modules/user';export default {NumberStore,UserStore, }
/src/mobx/modules/number.js
import { observable, action, makeObservable, computed } from "mobx";class NumberStore {constructor(){makeObservable(this)}// observable 表示数据可监控 表示是全局数据@observable name = "hello123";// action行为 表示 changeName是个可以修改全局共享数据的方法@action changeName(name) {this.name = name;}// 使用方法和name一样直接get即可@computed get total() {let newName = this.name + '最新的name值';return newName;} } export default new NumberStore();
/src/mobx/modules/user.js
import { observable, action, makeObservable } from "mobx";class UserStore {constructor(){makeObservable(this)}@observable userId = "userId123456";@action changeUserId(id) {this.userId = id;} }export default new UserStore();
App.js
import rootStore from "./src/mobx"; <Provider {...rootStore}></Provider>
/src/pages/home/index.js
@inject("NumberStore", "UserStore") @observer class Home extends React.Component {constructor(props){super(props)console.log('NumberStore.name', this.props.NumberStore.name);console.log('UserStore', this.props.UserStore.userId);} }
持久化数据存储
rn中没有localstorage, 并且早期提供的方法已无效, 需要使用第三方库实现数据的持久化存储.
react-native-storage: https://github.com/sunnylqm/react-native-storage
打包上线
安卓打包
https://www.react-native.cn/docs/signed-apk-android
按照官方文档操作即可
其他内容
ui组件库:
React Native Elements: https://reactnativeelements.com/docs/
Ant Design: https://rn.mobile.ant.design/docs/react/introduce-cn
NativeBase: https://github.com/GeekyAnts/NativeBase#6-components
动画库: https://github.com/lottie-react-native/lottie-react-native
官方推荐第三方库大全:
https://github.com/jondot/awesome-react-native
https://github.com/reactnativecn/react-native-guide
网盘下载基础参考文档:
链接: https://pan.baidu.com/s/1NAE-_nCtg_WY0LTmstEFSQ 密码: rr2c
最后: 更多内容请阅读官网入门文档模块 组件模块 及API模块
React Native 入门踩坑相关推荐
- linux平台安装React Native遇到的坑
3年前我在windows平台安装过React Native,我一直都记忆犹新,那个时候facebook刚推出支持安卓,然后花了一天的时间在自己的window电脑上配置好了,还是很兴奋的,安装博客地址如 ...
- React Native 入门实战视频教程(36 个视频)
React Native 入门实战视频教程(36 个视频) #1 React Native 课程介绍「02:14」 #2 搭建 React Native 开发与运行环境跑起来「05:07」 #3 演示 ...
- CMT2380/HC32L110入门踩坑记录
CMT2380/HC32L110入门踩坑记录 写在前面 1.空白工程启动文件的问题 2.RTC时钟问题 3.UART格式化输出的问题 4.SysTick进行延时 5.SW调试卡住或运行后卡住 6.pr ...
- 全志哪吒D1-H Tina Linux Ubuntu 22.04入门踩坑日记
哪吒D1-H Tina Linux入门踩坑日记 系统环境 源码编译 mklibs-readelf的C++标准问题 m4的SIGSTKSZ问题 libfakeroot的_STAT_VER问题 read_ ...
- React Native 入门实战视频教程(37 个视频)
我这里有视频教程,全部是我自己辛苦录的,有兴趣的可以看下. React Native 入门实战视频教程(37 个视频) 从零开始入门学习 React Native 开发,手把手教你写 App 项目 # ...
- React Native 入门实战视频教程(4 个视频)
React Native 入门实战视频教程(4 个视频) #1 React Native 课程介绍「02:14」 #2 搭建 React Native 开发与运行环境跑起来「05:07」 #3 演示在 ...
- 微信小程序入门踩坑记(妥妥的干货,新手快快看过来)
初次上手微信小程序,各种踩坑各种百度,草草扫过官网的文字,呃....表示记不住不想看,然后看了一本入门基础, 诺,就这本啦(链接:https://pan.baidu.com/s/15hKlDNpowU ...
- React Native入门(十二)之使用第三方字体文件
前言 项目中需要展示一些别的平面或者其他民族文字时,需要使用该文字对应的字体文件,一般来说都是.ttf的. 在React Native中,使用字体文件就是在style中设置fontFamily属性! ...
- 给iOS开发者的React Native入门使用教程
目录 一. 原生iOS项目集成React Native 二. 原生跳转RN页面 三. 显示豆瓣热门电影列表 四. 改为导航 五.完整源代码 一. 原生iOS项目集成React Native 创建一个新 ...
最新文章
- html层次选择器例题,JQuery 层次选择器的例子
- 数据库索引的实现原理及查询优化
- Mac,WIN下支撑 IPV6的 sftp客户端
- 【笔记】用正则匹配字符串的方法摘抄
- 微服务升级_SpringCloud Alibaba工作笔记0009---阿里云部署微服务_在内网不同机器上_报错_注册中心找不到对应的机器_遇到java.net.UnknownHostExceptio
- java 解析 ical_ical4j 实现ICS文件的生成和解析
- 关掉云存储后噪声 海康摄像头_万物互联 海量数据如何实现更好的存储和应用...
- html实现横向轮播,js实现横向轮播效果
- windows程序设计-王
- polkit启动失败_Linux MySQL 常见无法启动或启动异常的解决方案
- IP地址 网关是什么?网络概念
- 打造黑苹果(五)设置MACOS系统盘引导,以及安装驱动
- 深度解析B端设计规范如何落地?
- QT Review之 QSlider(滑块)
- long型转String(*)
- 开源无国界?你开源出去的代码, 可能有一天你自己都不能用了!
- 实验三 密码破解技术
- SQL Server 数据库基本操作入门篇【1】
- cscript和wscript之间的区别
- input自适应高度