共计 7879 个字符,预计需要花费 20 分钟才能阅读完成。
对于一项技术,我们不能停留在五分钟状态,特别喜欢一句话,用什么方式绘制 UI 界面一点不重要,重要的是底层的思维,解决问题和优化的思路。
由于 React
的生态极为庞大,本文内容部分来自一些别人的汇总,至于原文只要还是能找到的,我都会贴上地址,谢谢前期贡献的作者,如果有没有被汇总到的,欢迎在下面补充。
生态圈:
React
官方推荐超大型项目使用的TypeScript
- 为什么要把
TypeScript
放在第一位,因为TypeScript
在构建超大型应用时,多人协作可以极大的加快工作效率,特别是前后端交互特别多,业务情况特别复杂的状况下(比如IM
),它的优势就凸显出来了。但是在一些中小型项目中,优势并不是那么的明显。(比如做完项目跑路后期不迭代这种)
-
TypeScript
并不是一个新语言,可以简单的认为TS
=js + Type
. 它只是一个javascript
的超集,目前更新速度也是非常快,
- 个人建议,在
Node.js
开发和React native
以及大型React
中使用TypeScript
-
在下载官方的
react
脚手架中,包含了一个第三方的ts
创建脚手架的命令- 在
Create React App
中使用TypeScript
-
Create React App
内置了对 ·TypeScript` 的支持。 - 需要创建一个使用 TypeScript 的新项目,在终端运行:
npx create-react-app my-app --typescript
- 在
interface IState {collapsed?: boolean,}
interface IProps {props?: string | Function}
constructor(props: IState) {super(props)
}
flag :number = 123
componentDidMount() {const result = this.FunctionTest()
}
FunctionTest():Promise<number|string|object>{return Promise.resolve(false)
}
-
TypeScript
写起来代码量会多一些,但是对于参数类型,返回类型,一眼明了,拥有静态类型检查,如果有问题,在编写代码时候就可以知道。
补充一点,现在
TS
的生态已经足够适应开发,像一般的webpack
插件都有了typescript
的文件支持,当然,并不是所有的第三包都支持ts
. 在技术选型的时候就要考虑清楚这点,否则就会多做很多事情。
状态统一集中管理,redux,mbox,redux-sage,dva
等开源库
- 先看看原始的
react
数据管理
组件间数据的传递,依靠
props
,状态数据提升等完成,但是对于跨层级的组件间数据传递,就不那么友好了,尤其是大型项目后期的迭代维护
- 再说说被人吐槽,但是它的单向数据流思想不得不肯定的
redux
.
-
Redux
- 状态及页面逻辑从
<App/>
里面抽取出来, 成为独立的store
, 页面逻辑就是reducer
-
<TodoList/> 及 <AddTodoBtn/>
都是Pure Component
, 通过connect
方法可以很方便地给它俩加一层wrapper
从而建立起与store
的联系: 可以通过dispatch 向 store
注入action
, 促使store
的状态进行变化, 同时又订阅了 store 的状态变化, 一旦状态有变, 被connect
的组件也随之刷新 - 使用
dispatch
往store
发送action
的这个过程是可以被拦截的, 自然而然地就可以在这里增加各种Middleware
, 实现各种自定义功能,eg: logging
- 这样一来, 各个部分各司其职, 耦合度更低, 复用度更高, 扩展性更好
- 状态及页面逻辑从
在面试的时候,我觉得如果可以手写一个
redux
库,并且说清楚单向数据流的思维,是一个加分项。
- 最终推荐使用
dva
,感谢前辈的开源,解放了我们
-
dva
- 正如 Dva 官网所言, Dva 是基于 React + Redux + Saga 的最佳实践沉淀, 做了 3 件很重要的事情, 大大提升了编码体验
// 一个 dva 的模块文件 user.js
export default {
namespace: 'userinfo',
state: {
width: '-100%',
hasUserInfoActive: false,
info: undefined,
},
reducers: {
// 打开个人资料
open(state) {
return {
...state,
width: '0%',
hasUserInfoActive: true,
};
},
},
effects: {* init(res, { put, select}) {const { userinfo} = yield select();
if (userinfo.info === undefined) {
try {const list = yield DATABASE.Friend().getSelfInfo();
// console.log(list);
yield put({type: 'saveUserInfo', payload: list});
} catch (e) {console.error(e);
}
}
},
},
};
// user.jsx,业务组件文件
import {connect} from 'dva'
class App extends Component {componentDidMount(){
// 省掉了 mapActionsToPops 这一步
this.props.dispatch({type:"user/open"})
}
}
export default connect(
// 相当于 mapStateToState, 可以通过 this.props.user 拿到数据(({user})=>{user}))(App)
状态管理的最佳实践,应该说推荐
dva
,再次感谢前辈的开源。
UI
组件库,由于本人平时都不使用 UI
库了,所以可能会遗漏。
-
Ant-Design
,pc
版,制作后台管理系统的神器,同样要感谢前辈们的开源。- 关键字,
webpack
按需加载,配置默认样式,
- 关键字,
使用 babel-plugin-import(推荐)。// .babelrc or babel-loader option
{
"plugins": [
["import", {
"libraryName": "antd",
"libraryDirectory": "es",
"style": "css" // `style: true` 会加载 less 文件
}]
]
}
然后只需从 antd 引入模块即可,无需单独引入样式。等同于下面手动引入的方式。// babel-plugin-import 会帮助你加载 JS 和 CSS
import {DatePicker} from 'antd';
-
Ant-Degsin-mobile
- 关键字,按需加载,默认样式修改
使用 babel-plugin-import(推荐)。// .babelrc or babel-loader option
{
"plugins": [["import", { libraryName: "antd-mobile", style: "css"}]
// `style: true` 会加载 less 文件
]
}
然后只需从 antd-mobile 引入模块即可,无需单独引入样式。// babel-plugin-import 会帮助你加载 JS 和 CSS
import {DatePicker} from 'antd-mobile';
Ant Design Mobile RN of React
-
在
react-native
中使用Ant-Design
yarn add @ant-design/react-native
-
在
babel
配置中:"plugins": [["import", { libraryName: "@ant-design/react-native"}] ]
- 在
React-native
组件中使用:
import React from 'react';
import {View, Text, FlatList, SectionList, Alert} from 'react-native';
import {Button, Flex} from '@ant-design/react-native';
export default class Apps extends React.Component {render() {
return (
<View>
<Button
onPress={() => {Alert.alert(12312312);
}}
>
12345561
</Button>
</View>
);
}
}
Electron
,PC
端跨平台技术方案,集成Node
,可以开发极为复杂的应用
- 渲染进程和主进程采用
remote
模块或者ipc
通信方式进行通信,进而可以呼叫原生接口 - 完美解决
mac os
,windows
,linux
上的三端统一开发没有兼容性问题的框架 -
Electron
结合了Chromium、Node.js
和用于调用操作系统本地功能的API
(如打开文件窗口、通知、图标等) - 基于
Electron
的开发就像在开发网页,而且能够无缝地 使用Node
。或者说:在构建一个 Node 应用的同时,通过HTML 和 CSS
构建界面。另外,你只需为一个浏览器(最新的Chrome
)进行设计(即无需考虑兼容性等)
import React from 'react';
import {HashRouter, Route, Switch} from 'dva/router';
import {ipcRenderer, remote} from 'electron';
ipcRenderer.removeAllListeners();
ipcRenderer.on('loginSuccess', () => {ipcRenderer.send('reply', 'loginSuccess');
props.history.push('/login/loading');
props.dispatch({type: 'globalstate/saveStatus', payload: 1});
});
这是一个非常不错,而且考验一位前端工程师底层技术的框架,可能会写到大量底层
Node.js
和原生javascript
, 目前开发IM
项目很多使用这个框架。github
上的star
量也快80K
了。
react-native
,移动端跨平台框架
跨平台开发首选
Mac
,没有为什么
- 官方推荐的搭建原生完整环境方式
- 搭建完成后,执行
react-native run-ios
-
command+d
开启热更新
- 从
react
迁移到react-native
成本并不高,难的是适配和踩坑,遇到问题要多百度,rn
的生态也很强大,而且给我们封装了很多内容,也可以使用一些原生的接口.
React-native
的层次架构:
-
Java 层
:该层主要提供了Android 的 UI 渲染器 UIManager
(将 JavaScript 映射成 Android Widget)以及一些其他的功能组件(例如:Fresco、Okhttp)等,在 java 层均封装为 Module,java 层核心 jar 包是react-native.jar
,封装了众多上层的 interface,如 Module,Registry,bridge 等。 -
C++ 层
:主要处理Java 与 JavaScript
的通信以及执行 JavaScript 代码工作,该层封装了 JavaScriptCore,执行对 js 的解析。基于 JavaScriptCore,Web 开发者可以尽情使用 ES6 的新特性,如 class、箭头操作符等,而且 React Native 运行在JavaScriptCore
中的,完全不存在浏览器兼容的情况。Bridge 桥接了 java,js 通信的核心接口。JSLoader 主要是将来自 assets 目录的或本地 file 加载 javascriptCore,再通过 JSCExectutor 解析 js 文件。 -
Js 层
:该层提供了各种供开发者使用的组件以及一些工具库。 -
Component
:Js 层通 js/jsx 编写的 Virtual Dom 来构建 Component 或 Module,Virtual DOM 是 DOM 在内存中的一种轻量级表达方式,可以通过不同的渲染引擎生成不同平台下的 UI。component 的使用在 React 里极为重要, 因为 component 的存在让计算 DOM diff 更高效。 -
ReactReconciler
: 用于管理顶层组件或子组件的挂载、卸载、重绘。
注:JSCore,即 JavaScriptCore,JS 解析的核心部分,IOS 使用的是内置的 JavaScriptCore,Androis 上使用的是
https://webkit.org
家的 jsc.so。启动过程的解析:
- 1.
ReactInstanceManager
创建时会配置应用所需的 java 模块与 js 模块,通过ReactRootView
的startReactApplication 启动 APP
。 - 2. 在创建
ReactInstanceManager
同时会创建用于加载 JsBundle 的 JSBundlerLoader,并传递给CatalystInstance
。 - 3.
CatalystInstance
会创建 Java 模块注册表及 Javascript 模块注册表,并遍历实例化模块。 - 4.
CatalystInstance 通过 JSBundlerLoader
向 Node Server 请求 Js - Bundle,并传递给 JSCJavaScriptExectutor,最后传递给 javascriptCore,再通过 ReactBridge 通知 ReactRootView 完成渲染。
Js 与 Java 通信机制
- Java 与 Js 之间的调用,是以两边存在两边存在同一份模块配置表,最终均是将调用转化为{moduleID,methodID,callbackID,args},处理端在模块配置表里查找注册的模块与方法并调用。
Java
调用Js
-
Java
通过注册表调用到CatalystInstance
实例,透过 ReactBridge 的 jni,调用到 Onload.cpp 中的 callFunction,最后通过 javascriptCore,调用 BatchedBridge.js,根据参数{moduleID,methodID}require 相应 Js 模块执行。流程如下图:
- Js 调用 Java
- 如果消息队列中有等待
Java
处理的逻辑,而且Java 超过 5ms
都没有来取走,那么JavaScript
就会主动调用Java
的方法, 在需要调用调Java
模块方法时,会把参数{moduleID,methodID}
等数据存在MessageQueue
中,等待 Java 的事件触发,把MessageQueue
中的{moduleID,methodID}返回给 Java
,再根据模块注册表找到相应模块处理。流程如下图:
参考文章,react-native 原理解析, 看在
react-native
跨平台开发的无缝对接js 和 react
份上,我决定坚定使用它。希望在 1.0 版本到来的时候,给我们一个惊喜。
京东的Taro
,多端解决方案
-
Taro
是一套遵循React
语法规范的 多端开发 解决方案。现如今市面上端的形态多种多样,Web、React-Native、
微信小程序等各种端大行其道,当业务要求同时在不同的端都要求有所表现的时候,针对不同的端去编写多套代码的成本显然非常高,这时候只编写一套代码就能够适配到多端的能力就显得极为需要。 - 使用
Taro
,我们可以只书写一套代码,再通过Taro
的编译工具,将源代码分别编译出可以在不同端(微信 / 百度 / 支付宝 / 字节跳动小程序、H5、React-Native
等)运行的代码。
- 代码示例:
import Taro, {Component} from '@tarojs/taro'
import {View, Button} from '@tarojs/components'
export default class Index extends Component {constructor () {super(...arguments)
this.state = {
title: '首页',
list: [1, 2, 3]
}
}
componentWillMount () {}
componentDidMount () {}
componentWillUpdate (nextProps, nextState) {}
componentDidUpdate (prevProps, prevState) {}
shouldComponentUpdate (nextProps, nextState) {return true}
add = (e) => {// dosth}
render () {
return (
<View className='index'>
<View className='title'>{this.state.title}</View>
<View className='content'>
{this.state.list.map(item => {
return (<View className='item'>{item}</View>
)
})}
<Button className='add' onClick={this.add}> 添加 </Button>
</View>
</View>
)
}
}
- 关键字,编译成不同的平台应用输出
-
Taro
拥有自己的脚手架 脚手架配置
为什么会加入
Taro
, 因为它是国产,基于react
, 应该支持。而且相信未来它应该有不错的前景。
-
环境搭建:
- 首先,你需要使用 npm 或者 yarn 全局安装 @tarojs/cli,或者直接使用 npx:
- $
yarn global add @tarojs/cli
- 使用命令创建模板项目 $
taro init myApp
- 选择微信小程序模式,需要自行下载并打开微信开发者工具,然后选择项目根目录进行预览。
- 微信小程序编译预览及打包(去掉 –watch 将不会监听文件修改,并会对代码进行压缩打包)
# yarn
$ yarn dev:weapp
$ yarn build:weapp
# npm script
$ npm run dev:weapp
$ npm run build:weapp
# 仅限全局安装
$ taro build --type weapp --watch
$ taro build --type weapp
# npx 用户也可以使用
$ npx taro build --type weapp --watch
$ npx taro build --type weapp
- H5 模式,无需特定的开发者工具,在执行完下述命令之后即可通过浏览器进行预览
# yarn
$ yarn dev:h5
# npm script
$ npm run dev:h5
# 仅限全局安装
$ taro build --type h5 --watch
# npx 用户也可以使用
$ npx taro build --type h5 --watch
React Native
# yarn
$ yarn dev:rn
# npm script
$ npm run dev:rn
# 仅限全局安装
$ taro build --type rn --watch
# npx 用户也可以使用
$ npx taro build --type rn --watch
Taro
也拥有自己的生态圈,非常庞大,非常感谢京东的开源,希望它的功能越来越强大。
最终总结:
-
React
本身很强大,生态圈非常强大,可以说任何平台的大型应用都可以让它来做,加上hook
的出现,未来可期。 - 用什么框架,什么技术绘制
UI
并不重要,但是本人觉得js
和react
的无缝对接下更偏向rn
,taro
,electron
这类型的框架开发跨平台应用。 - 后期会再出关于
react
的优化汇总,觉得写得不错的可以点个赞~谢谢