# react-native-app **Repository Path**: lukangfeng/react-native-app ## Basic Information - **Project Name**: react-native-app - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2019-07-30 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # React-Native踩坑 [TOC] ## 配置 1. 配置依赖 2. 配置路径别名 3. 配置路由router 4. 配置仓库store 5. 配置~~Sass~~,采用css,scss文件自动转换成react native直接引用的样式文件 ### 配置依赖 > [插件总结](https://www.jianshu.com/p/d6f216e7b358) 1. 安装UI框架 react-base ``` yarn add native-base ``` 2. 安装路由 react-native-router-flux【自带顶部栏与底部Tab选项栏】 ``` yarn add react-native-router-flux ``` 3. 安装图标 react-native-vector-icons【底部选项的图标也可以使用】 ``` yarn add react-native-vector-icons ``` 4. 时间格式 moment ``` yarn add moment ``` 5. 数据请求 axios ``` yarn add axios ``` 6. 图片处理(ps:自适应等)react-native-fit-image :对于不同的移动尺寸,以响应式风格制作图像 ``` yarn add react-native-fit-image ``` 7. 时间处理 react-native-timeago 此包有助于将时间戳转换为时间前的文本 ``` yarn add react-native-timeago ``` 8. 第三方轮播 react-native-swiper ``` yarn add react-native-swiper ``` 9. redux的中间件redux-saga ``` yarn add redux-saga ``` 10. redux中间件 redux-saga / redux-logger ``` yarn add redux-saga redux-logger ``` ### 配置别名 配置tsconfig.json > "@/*": ["*"] ,单独src的别名-----》package.json>>>{"name": "@"} ``` "baseUrl": "src", "paths": { "@components/*": ["components/*"], "@views/*": ["views/*"], "@/*": ["*"] } ``` 最后在views目录下新建package.json ``` { "name": "@views" } ``` ### 配置路由 router/index.ts ``` import Home from "@views/home"; import Product from "@views/product"; import Sort from "@views/sort"; import Cart from "@views/cart"; import User from "@views/user"; export default { Home, Product, Sort, Cart, User }; ``` ### 配置仓库 #### api配置 采用axios配置api,(一种配法)**因业务/项目来变更配置**,大致的不会变 ``` import axios from "axios"; let defaultConfig = { timeout: 3000, baseURL: "https://climber-zkc.xyz/api/react-mobile-mall" }; //axios,初始化 let instance: any = axios; //定义一个类 class Axios { //构造函数,创建一个类 constructor(props) { //props是undefind或者不是object就使用默认配置 if (props && typeof props == "object") { instance = axios.create(props); } else { instance = axios.create(defaultConfig); } //请求拦截器 instance.interceptors.request.use( config => { console.log(config); //直接发送请求,不做任何处理 return config; }, error => { console.log(error); return Promise.reject(error); } ); //响应拦截器 instance.interceptors.response.use( response => { //直接返回请求结果,不做任何处理 return response.data; }, error => { console.log(error); return Promise.reject(error); } ); } //send方法 send(params: any) { console.log(params); if (!params || typeof params != "object") { throw new Error("params is undefined or not an object"); } if (params.method == "get") { return get(params.url); } else if (params.method == "post") { return post(params.url); } else if (params.method == "put") { return put(params.url); } else if (params.method == "patch") { return patch(params.url); } else if (params.method == "delete") { return deletes(params.url); } } } //异步get请求类型的方法 async function get(url: string) { try { let response = await instance.get(url); return response; } catch (e) { console.log(e); } } //异步post请求类型的方法 async function post(url: string) { try { let response = await instance.post(url); //return callback(response) return response; } catch (e) { console.log(e); } } //异步delete请求类型的方法 async function deletes(url: string) { try { let response = await instance.delete(url); //return callback(response) return response; } catch (e) { console.log(e); } } //异步put请求类型的方法 async function put(url: string) { try { let response = await instance.put(url); //return callback(response) return response; } catch (e) { console.log(e); } } //异步patch请求类型的方法 async function patch(url: string) { try { let response = await instance.patch(url); //return callback(response) return response; } catch (e) { console.log(e); } } let Instance = new Axios({ timeout: 8000, baseURL: "https://climber-zkc.xyz/api/react-mobile-mall" }); //暴露实例化这个Axios类里面的方法 export default Instance; ``` #### 请求配置 ``` import HttpUtils from "./https"; class Https { newsLists = (parmas: any) => { return HttpUtils.send({ url: `/news?page=${parmas}&pagesize=8`, method: "get" }); }; } export default new Https(); ``` #### 仓库配置 ``` //利用createStore把reducer数据中心的属性或者方法映射到store,之后通过Provider传递给组件 //applyMiddleware,添加中间件 //applyMiddleware 函数的作用就是对 store.dispatch 方法进行增强和改造,使得在发出 Action 和执行 Reducer 之间添加其他功能。 import { createStore, applyMiddleware } from "redux"; import createSagaMiddleware from "redux-saga"; import logger from "redux-logger"; import mySaga from "../sagas"; import reducer from "../reducers"; //实例化redux-saga的createSagaMiddleware创建一个saga方法中间件 const sagamiddleware = createSagaMiddleware(); //配置仓库 export default () => { //sagamiddleware中间件加入到middlewaress数组 const middlewares = [sagamiddleware]; //React Native中有一个全局变量__DEV__用于指示当前运行环境是否是开发环境 if (__DEV__) { //开发环境引入logger middlewares.push(logger); } //引用中间件创建仓库 const createStoreMiddleware = applyMiddleware(...middlewares)(createStore); //创建数据中心连接仓库 // const store = createStore(reducer, applyMiddleware(...middlewares)); const store = createStoreMiddleware(reducer); // console.log(store); //运行saga,或者这样写sagaMiddleware.run(mySaga),mySaga是引入的saga文件 sagamiddleware.run(mySaga); return store; }; ``` #### 简单述说一下仓库流程(react-redux可以深入---》有个按需引用) ##### 1. 建立行为【Action】 ``` const News = { GET_MANY_NEWS: "GET_MANY_NEWS" }; //action这边只定义(规范)所有的行为类型type export function fetchNewData(parmas) { // console.log('parmas') return { type: News.GET_MANY_NEWS, parmas }; } ``` ##### 2. 因为运用了redux-saga--》(ps采用了ES6的Generator/yield* 表达式)中间件(解决异步的),建立监控行为(简单应用)----》这里可以深入 1. takeEvery 用来监听action,每个action都触发一次,如果其对应是异步操作的话,每次都发起异步请求,而不论上次的请求是否返回。 2. takeLatest 作用同takeEvery一样,唯一的区别是它只关注最后,也就是最近一次发起的异步请求,如果上次请求还未返回,则会被取消。 3. call call用来调用异步函数,将异步函数和函数参数作为call函数的参数传入,返回一个js对象。saga引入他的主要作用是方便测试,同时也能让我们的代码更加规范化。 4. put put是saga对Redux中dispatch方法的一个封装,调用put方法后,saga内部会分发action通知Store更新state。这个借口主要也是为了方便我们写单元测试提供的。 5. all all提供了一种并行执行异步请求的方式。之前介绍过执行异步请求的api中,大都是阻塞执行,只有当一个call操作放回后,才能执行下一个call操作, call提供了一种类似Promise中的all操作,可以将多个异步操作作为参数参入all函数中,如果有一个call操作失败或者所有call操作都成功返回,则本次all操作执行完毕 ---参考[Redux-saga--API](https://redux-saga.js.org/docs/api/) ``` import https from "@/api"; import { all, call, put, takeLatest } from "redux-saga/effects"; export function* newsList(actions: any) { try { const data = yield call(https.newsLists, actions.parmas); yield put({ type: "GETSUCCESS", data }); } catch (err) { yield put({ type: "GETFAIL" }); } } //默认暴露先执行 export default function* root() { // console.log("object"); //takeLatest解决并发操作 yield all([takeLatest("GET_MANY_NEWS", newsList)]); } ``` ##### 3. Reducer数据处理中心处理返回回来的行为type做出数据处理 ``` const initState = { newsList: [] }; //数据处理中心(通过方法/请求数据等都需要经过reducer) //基本从actions来 const Newslist = (state = initState, actions) => { //接收到Succsee,就把接收到的数据存放到newsList // console.log(actions.data); switch (actions.type) { case "GETSUCCESS": //合并数据到data里 return { ...state, newsList: actions.data }; case "GETFAIL": //合并数据到data里 return state; default: return state; } }; export default Newslist; ``` ##### 4. 组件的处理就是触发事件(触发行为) ``` //引入action的规范 import * as homeAction from "@/actions/home"; //bindActionCreators不需要子组件知道有redux import { bindActionCreators, Dispatch } from "redux"; //连接state和props映射 import { connect } from "react-redux"; -------------------------------------------------------------------------- //获取数据(新闻) getList = async () => { //这边只发起请求 const { actions: { fetchNewData } } = this.props; await fetchNewData(1); }; componentDidMount() { this.getList(); } --------------------------------------------------------- //State属性映射 const mapStateToProps = (state: any, props: any) => ({ Data: state.home.newsList //传递数据到Data,子组件接收到data }); //映射异步请求方法(发送homeAction行为) const mapDispatchToProps = (dispatch: Dispatch) => ({ actions: bindActionCreators(homeAction, dispatch) }); export default connect( mapStateToProps, mapDispatchToProps )(Home); ``` #### 配置~~Sass~~,css/sass文件自动转换成react-native样式文件。 [介绍出处地址](http://bbs.reactnative.cn/topic/6604/web前端开发rn的福音-css-scss文件自动转换成react-native直接引用的样式文件) 在react-native用sass预处理css是个很糟糕的注意,比如react-native没有像素单位,sass必须带单位 ## 存在的共有组件部分 1. 轮播 2. 下拉刷新/上拉加载 3. 九宫格 4. 。。。。。 ## 架构App.tsx主模块 安装路由模块 ``` yarn add react-native-router-flux ``` 配置底部tab选项卡 ps:**react-native-router-flux**自带tab选项卡与顶部栏 解读: 1. Stack是为堆栈,先进后出【Tab选项卡】,(基于堆栈实现的导航:场景组合在一起的组件) 1. 需要有唯一的key,title属性是属于Tab选项卡的title 2. Scene是为场景,多个场景可以被Stack包裹,公用顶部/底部等,**必须要有一个唯一的 key** 1. title为顶部栏的名字 2. initial是设置默认页 3. navBar设置自定义顶部栏 3. Stack设置图标 1. icon属性引入组件 2. iconName在Stack不存在该属性,需要改源代码iconName?:string,iconName是传递给TabIcon的图标名 3. TabIcon组件源代码 4. Tab属性是配置底部Tab选项卡 ![Tab属性介绍](_v_images/20190727015014351_19353.png =579x) ### 配置底部图标组件 **import Icon from "react-native-vector-icons/SimpleLineIcons**,很重要,没有大括号 ``` import React from "react"; // 引入SimpleLineIcons图标库 import Icon from "react-native-vector-icons/SimpleLineIcons"; const TabIcon = props => { return ( ); }; export default TabIcon; ``` ### 主组件路由基础源代码 #### 路由 ``` 。。。。。 ``` #### 自定义底部导航栏 **使用StatusBar,可以使得状态栏消失等操作** ```