ReactNative进阶(三十五):应用脚手架 Yo 构建 RN 页面

2024-02-16 18:48

本文主要是介绍ReactNative进阶(三十五):应用脚手架 Yo 构建 RN 页面,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 一、前言
    • 二、Bloc 数据流讲解
    • 三、利用代码自动生成功能创建新页面
    • 四、Bloc数据流使用说明
    • 五、拓展阅读


一、前言

在前期博文《ReactNative进阶(三十二):前端构建工具–Yeoman》中将脚手架yo安装成功,本篇博文主要讲解如何利用yo提供的代码自动生成功能生成项目代码。

二、Bloc 数据流讲解

Bloc 数据流工具安装:

sudo npm install -g yo
sudo npm install -g generator-bloc

安装完成后通过执行 npm ls generator-bloc -g 命令,查看bloc模板生成位置。执行结果如下:

在这里插入图片描述

进入node_modules目录,可看到生成的generator-bloc文件夹,进入该文件夹,查看README.md文件。

文件内容如下:


> # generator-bloc [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency
> Status][daviddm-image]][daviddm-url] [![Coverage
> percentage][coveralls-image]][coveralls-url]
> > react-bloc cli
> 
> ## Installation
> 
> First, install [Yeoman](http://yeoman.io) and generator-bloc using
> [npm](https://www.npmjs.com/) (we assume you have pre-installed
> [node.js](https://nodejs.org/)).
> 
> ```bash npm install -g yo npm install -g generator-bloc ```
> 
> Then generate your new project:
> 
> ```bash yo bloc ```
> 
> ## Getting To Know Yeoman
> 
>  * Yeoman has a heart of gold.  
>  * Yeoman is a person with feelings and opinions, but is very easy to work with.  
>  * Yeoman can be too opinionated at times but is easily convinced not to be.  
>  * Feel free to [learn more about Yeoman](http://yeoman.io/).
> 
> ## License
> 
> MIT © [MeePwn](https://github.com/maybewaityou)
> 
> 
> [npm-image]: https://badge.fury.io/js/generator-bloc.svg [npm-url]:
> https://npmjs.org/package/generator-bloc [travis-image]:
> https://travis-ci.org/maybewaityou/generator-bloc.svg?branch=master
> [travis-url]: https://travis-ci.org/maybewaityou/generator-bloc
> [daviddm-image]:
> https://david-dm.org/maybewaityou/generator-bloc.svg?theme=shields.io
> [daviddm-url]: https://david-dm.org/maybewaityou/generator-bloc
> [coveralls-image]:
> https://coveralls.io/repos/maybewaityou/generator-bloc/badge.svg
> [coveralls-url]: https://coveralls.io/r/maybewaityou/generator-bloc

三、利用代码自动生成功能创建新页面

此处以新建test界面为例介绍使用bloc创建界面的方法步骤,页面新建在项目中page-new目录下。

  1. 进入项目根目录输入命令:yo bloc 回车;
  2. 弹出选择界面后使用上下移动键选择: create a new page. 回车;
  3. 输入页面名字:test 回车;
  4. 选择语言:js 回车;
  5. 输入模块路径:src/page-new 回车;
  6. 选择新建页面所在的模块:home 回车;
  7. 选择平台:react-native 回车;
  8. 待页面创建完成,未报错则说明页面创建成功;

在这里插入图片描述

通过以上步骤信息结合项目结构可知,

脚手架yo为我们新生成了以下文件

  • home/view/TestView.js
  • home/bloc/TestBloc.js
  • home/bloc/interactor/TestUserCase.js
  • home/bloc/data/source/TestRepository.js
  • home/bloc/data/source/local/TestLocalDataSource.js
  • home/bloc/data/source/remote/TestRemoteDataSource.js

home/bloc/ioc/types.js文件中新增bloc标识:

export const DATA_SOURCE_TYPES = {HomeRemoteDataSource: Symbol.for('HomeRemoteDataSource'),HomeLocalDataSource: Symbol.for('HomeLocalDataSource'),TestRemoteDataSource: Symbol.for('TestRemoteDataSource'),TestLocalDataSource: Symbol.for('TestLocalDataSource'),
};export const USE_CASE_TYPES = {HomeUseCase: Symbol.for('HomeUseCase'),TestUseCase: Symbol.for('TestUseCase'),
};export const REPOSITORY_TYPES = {HomeRepository: Symbol.for('HomeRepository'),TestRepository: Symbol.for('TestRepository'),
};export const BLOC_TYPES = {HomeBloc: Symbol.for('HomeBloc'),TestBloc: Symbol.for('TestBloc'),
};

bloc/ioc/register.js文件中新增容器配置:

import TestBloc from '../TestBloc';
import TestUseCase from '../interactor/TestUseCase';
import TestRepository from '../data/source/TestRepository';
import { TestRemoteDataSource } from '../data/source/remote/TestRemoteDataSource';
import { TestLocalDataSource } from '../data/source/local/TestLocalDataSource';container.bind(DATA_SOURCE_TYPES.TestRemoteDataSource).to(TestRemoteDataSource);
container.bind(DATA_SOURCE_TYPES.TestLocalDataSource).to(TestLocalDataSource);
container.bind(REPOSITORY_TYPES.TestRepository).to(TestRepository);
container.bind(USE_CASE_TYPES.TestUseCase).to(TestUseCase);
container.bind(BLOC_TYPES.TestBloc).to(TestBloc);

home/route-config/HomeRouteConfig.js将新建页面添加到路由中;

将TestView添加到export中即可使用router.navigate(“TestView”)跳转到该页面。

注:本项目路由使用routerimport { router } from 'mario-navigation-extension';

四、Bloc数据流使用说明

在这里插入图片描述

bloc数据流采用stream-builder的形式绑定数据,当stream绑定的数据有改变时,builder便会重新渲染界面,类似于RNsetState,下面以刚创建的 TestView 为例介绍使用步骤:

首先,该页面的入口文件为src/page-new/view/TestView.js, 该界面只写view渲染相关代码,export default ( ) ... 方法即为页面入口,该方法可接收路由传递的参数,可在此方法完成参数初始化,如果该页面需要在未被销毁的情形下多次加载,可以使用try catch 初始化,container.get(BLOC_TYPES.TestBloc)方法会完成bloc的唯一注册,只会在第一次初始化时渲染界面,重新渲染需要使用BlocProvider.of(BLOC_TYPES.TestBloc),因此多次加载同一界面可以使用如下代码:

export default (props) => {let _bloc = null;try {_bloc = BlocProvider.of(BLOC_TYPES.TestBloc);} catch (error) {_bloc = container.get(BLOC_TYPES.TestBloc);}const params = props.navigation.state.params;_bloc.init(params);return <BlocProvider bloc={_bloc} child={_viewBuilder} />;
};

其中init方法在 TestBloc 中定义。

接下来便是_viewBuilder中的界面UI:

function _viewBuilder() {const _bloc = BlocProvider.of(BLOC_TYPES.TestBloc);return (<View style={style.container}><StreamBuilder stream={_bloc.viewState$} builder={_testBuilder} /><StreamBuilder stream={_bloc.listData$} builder={_listBuilder} /></View>);
}

其中stream为TestBloc中定义的数据,builder为界面UIbuilder会获取绑定数据的快照snapshotsnapshot.data即为绑定的数据。

function _testBuilder(snapshot){if(snapshot.hasData){return (<Text>{JSON.stringify(snapshot.data)}</Text>)} else return (<View></View>)
}

stream可以绑定多个数据流:

<StreamBuilder stream={_bloc.listData$.pipe(combineLatest(_bloc.searchObj$))}builder={_userListBuilder} />

页面数据定义在 src/page-new/home/bloc/TestBloc.js中,

listData = {viewState: {isRefresh: false,isLoading: true,hasMore: true,hint: '加载中...',pageNo: '1',pageSize: '15',},list: [],data: {},};listData$ = new EnhanceSubject(this.listData);viewState = {open: false,pickerItems: [{ text: '待发货', handleFlag: '1' }, { text: '已发货', handleFlag: '2' }],pickedItem: {text: '待发货',handleFlag: '1',},totalSize: 0,};viewState$ = new EnhanceSubject(this.viewState);

listData$即为 TestView 中绑定的数据,当listData$改变时界面就会重新渲染,例如:

init = (params) => {this.listData= processModify(this.listData, {viewState: {isRefresh: params.isRefresh,isLoading: params.isLoading,hint: '加载中...'},	});this.listData$.add(this.listData); // 相当于RN的setState};

注⚠️:定义在TestBloc中的方法建议使用箭头函数,防止this指向跑偏。

网络请求使用封装好的WebService: src/main/service/WebService.js,WebService的BaseUrl为:src/main/constant/Constant.jsBASE_URL,请求参数有个meta数据,该meta数据会在真正请求前删除,使用meta: { silence: true }可以在请求时不展示Loading框,默认会加载Loading框。

bloc中定义异步接口方法,

queryList = async (refresh, handleFlag) => {let index = refresh ? '1' : this.listData.viewState.pageNo;this.listData = processModify(this.listData, {viewState: {...this.listData.viewState,isRefresh: refresh,isLoading: !refresh,hint: '加载中...'},});this.listData$.add(this.listData); // 发起请求时刷新界面状态// 使用userCase调用接口,返回的是两个对象,第一个为接口报错(非业务逻辑错)时的对象,第二个为接口正常返回的对象const [error, data] = await this.useCase.execute({bizline: '4',tasktyp: '25',handleFlag: handleFlag || this.viewState.pickedItem.handleFlag,pageNo: index,pageSize: this.listData.viewState.pageSize,meta: { silence: true },});if (error) {...this.listData$.add(this.listData); // 接口报错时更新界面UIreturn;}let hasList = this.listData.list || [];if (refresh) {hasList = [];}let list = data.resultList;let isMore = list.length >= parseInt(this.listData.viewState.pageSize);let hint = '';if (hasList.length < 1 && list.length < 1) {hint = '抱歉~没有相关信息';}this.listData = processModify(this.listData, {list: hasList.concat(list),data,viewState: {...this.listData.viewState,isRefresh: false,isLoading: false,hasMore: isMore,pageNo: `${parseInt(index) + 1}`,hint: hint || (isMore ? '加载更多' : '没有更多了'),}});this.listData$.add(this.listData); // 请求得到后台数据后刷新界面数据this.viewState = processModify(this.viewState, {totalSize: data.totalSize,});this.viewState$.add(this.viewState); // 刷新界面状态};

在对应的TestUseCase.js中添加:

buildUseCasePromise(params) {return this.repository.queryList(params);
}

添加接口参数,也就是this.useCase.execute传过来的参数,userCase的excute方法对应执行的是buildUseCasePromise方法,如果是其它方法需要自定义:

  handleCheck(params) {return to(this.repository.handleCheck(params));}

此时需要将结果用to包裹,以规范返回数据的格式:

import { to } from '../../../../main/utilities';

调用自定义方法时,需要将bloc里的调用方法由this.useCase.execute({})改为this.useCase.handleCheck({});

然后定义数据流策略,使用远程服务器数据还是本地数据库数据(定义在src/page-new/home/bloc/data/source/TestRepository.js:):

queryList(params) {return this.remoteDataSource.queryList(params);
}

在该处可以进行数据的并行或者串行请求或者数据的其它一些处理,如下代码所示:

async queryList(params) {const data = await this.remoteDataSource.queryList({ meta: { silence: true } });if (data.list.length > 0) {let customeridStr = '';data.list.forEach((item) => {customeridStr += item.customerid + ',';});// 串行接口const signalData = await this.remoteDataSource.queryNewsTheme({ customeridStr, flag: 'index', ...params, meta: { silence: true } });let listIndex = []for (let i = 0; i < signalData.listIndex.length; i++) {...}return { totalSize: signalData.totalSize, listIndex };} else {return { 'listIndex': [] }}}

最后就是调用TestRemoteDataSource.js中的webService请求后台接口:

queryList(params) {return this.webService.request(queryTaskPageList, params);}

其中params是从TestRepository.js传过来的,queryTaskPageList为接口名称,需要自定义:

const queryTaskPageList = 'queryTaskPageList'; 

其中,webService是从工具类arch中引入的:

import { PROCESSOR } from '@arch';

数据流如下图所示:
在这里插入图片描述

五、拓展阅读

  • 《ReactNative进阶(三十二):前端构建工具–Yeoman》
  • 《ReactNative进阶(三十一): IoC 框架 InversifyJS解读》
  • 《ReactNative进阶(二十九):BloC模式》

这篇关于ReactNative进阶(三十五):应用脚手架 Yo 构建 RN 页面的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/715382

相关文章

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

从基础到进阶详解Pandas时间数据处理指南

《从基础到进阶详解Pandas时间数据处理指南》Pandas构建了完整的时间数据处理生态,核心由四个基础类构成,Timestamp,DatetimeIndex,Period和Timedelta,下面我... 目录1. 时间数据类型与基础操作1.1 核心时间对象体系1.2 时间数据生成技巧2. 时间索引与数据

基于Python构建一个高效词汇表

《基于Python构建一个高效词汇表》在自然语言处理(NLP)领域,构建高效的词汇表是文本预处理的关键步骤,本文将解析一个使用Python实现的n-gram词频统计工具,感兴趣的可以了解下... 目录一、项目背景与目标1.1 技术需求1.2 核心技术栈二、核心代码解析2.1 数据处理函数2.2 数据处理流程

Python FastMCP构建MCP服务端与客户端的详细步骤

《PythonFastMCP构建MCP服务端与客户端的详细步骤》MCP(Multi-ClientProtocol)是一种用于构建可扩展服务的通信协议框架,本文将使用FastMCP搭建一个支持St... 目录简介环境准备服务端实现(server.py)客户端实现(client.py)运行效果扩展方向常见问题结

详解如何使用Python构建从数据到文档的自动化工作流

《详解如何使用Python构建从数据到文档的自动化工作流》这篇文章将通过真实工作场景拆解,为大家展示如何用Python构建自动化工作流,让工具代替人力完成这些数字苦力活,感兴趣的小伙伴可以跟随小编一起... 目录一、Excel处理:从数据搬运工到智能分析师二、PDF处理:文档工厂的智能生产线三、邮件自动化:

Python使用Tkinter打造一个完整的桌面应用

《Python使用Tkinter打造一个完整的桌面应用》在Python生态中,Tkinter就像一把瑞士军刀,它没有花哨的特效,却能快速搭建出实用的图形界面,作为Python自带的标准库,无需安装即可... 目录一、界面搭建:像搭积木一样组合控件二、菜单系统:给应用装上“控制中枢”三、事件驱动:让界面“活”

详解如何使用Python从零开始构建文本统计模型

《详解如何使用Python从零开始构建文本统计模型》在自然语言处理领域,词汇表构建是文本预处理的关键环节,本文通过Python代码实践,演示如何从原始文本中提取多尺度特征,并通过动态调整机制构建更精确... 目录一、项目背景与核心思想二、核心代码解析1. 数据加载与预处理2. 多尺度字符统计3. 统计结果可

如何确定哪些软件是Mac系统自带的? Mac系统内置应用查看技巧

《如何确定哪些软件是Mac系统自带的?Mac系统内置应用查看技巧》如何确定哪些软件是Mac系统自带的?mac系统中有很多自带的应用,想要看看哪些是系统自带,该怎么查看呢?下面我们就来看看Mac系统内... 在MAC电脑上,可以使用以下方法来确定哪些软件是系统自带的:1.应用程序文件夹打开应用程序文件夹

Python Flask 库及应用场景

《PythonFlask库及应用场景》Flask是Python生态中​轻量级且高度灵活的Web开发框架,基于WerkzeugWSGI工具库和Jinja2模板引擎构建,下面给大家介绍PythonFl... 目录一、Flask 库简介二、核心组件与架构三、常用函数与核心操作 ​1. 基础应用搭建​2. 路由与参

Spring Boot中的YML配置列表及应用小结

《SpringBoot中的YML配置列表及应用小结》在SpringBoot中使用YAML进行列表的配置不仅简洁明了,还能提高代码的可读性和可维护性,:本文主要介绍SpringBoot中的YML配... 目录YAML列表的基础语法在Spring Boot中的应用从YAML读取列表列表中的复杂对象其他注意事项总