最近基本都是在研究及实现react 移动端项目,这里做一个有关react 的总结,以便之后深入理解与使用
首先react 最初来自Facebook内部的广告系统项目,与之后的Vue 一样,核心解决的问题是数据绑定避免操作大量真实DOM 。本质上还是遵循模块化理念,实现View 层的渲染视图。主要操作包括:模块定义、接口暴露、模块引入、模块调用。它鲜明的一个特性就是组件化开发,通过组件实现视图的渲染。一个组件内可以实现数据请求、H5页面渲染、组件嵌套、传递参数并返回结果等一系列围绕数据进行的渲染操作。
当然为了达到最终的视图渲染,还需要处理的关键问题是数据的管理。react 提出的是进行状态管理,也就是如何处理state。这里使用的 Redux(与 Redux 对比的flux 区别暂不具体阐述),下面就Redux 做一个简单总结。
Redux 中可以分为5个主要内容():Store、Action、Components、Routes、Reducer
也许这张图看的有点懵,这里重点解释一下。从最底端的用户开始,用户看到的实际是组件 components 中的内容,而它的上级Containers 可以简单理解为用户打开的App 或者 小程序这样一个概念。那么这时候会提出一个疑问,components 是视图层,那它的数据会从哪里来?这时再往上追溯到 Store 层,这里从Containers 到 Components 会有一句话,放大了看就是
“无论何时当应用的state 改变时,组件会重新被渲染”,而 Container 的上级Provider 说的是,“让所有Container 可以获取到store 里的数据。” 。
这里结合到实际项目中就是,store 作为数据的“存储仓库”,提供给 react-dedux 暴露出来的 Provide 的所有子组件使用(这里暂时不必深究其他组件的作用)。下图给的是移动端里的App.js ,也就是整个项目的入口文件。这里还有一块内容Router 是第一张大图没有提及的。将在文章的最后一部分分析。
import React from 'react';
import { StyleSheet,View,SafeAreaView,Text,Image,Dimensions} from 'react-native';
import {Font,AppLoading} from 'expo';
import { Ionicons } from '@expo/vector-icons';
import { Peoples,HomeScene,DetailsScene,NewsScene,NewsDetailsScene,ProductScene,ProductDetailsScene,UserScene} from './scenes'
import {Router,Stack,Scene,Tabs} from 'react-native-router-flux'
import { TabIcon,HomeNavBar,Camera,NewsNavBar,UserNavBar} from './components'
import {Provider} from 'react-redux'
import store from './store'
export default class App extends React.Component {
state={
loading:true
}
async componentDidMount() {
await Font.loadAsync({
'Roboto' : require('./node_modules/native-base/Fonts/Roboto.ttf'),
'Roboto_medium': require('./node_modules/native-base/Fonts/Roboto_medium.ttf'),
...Ionicons.font,
});
this.setState({
loading:false
})
}
render() {
if(this.state.loading){
return
}else{
return (
// Router 路由操作
);
}
}
}
而 store 中的内容是:
import { createStore,applyMiddleware } from 'redux';
import reducers from '../reducers'
import thunk from 'redux-thunk';
const store = createStore(reducers,applyMiddleware(thunk));
export default store;
这里调用 redux 中的两个方法 createStore 和 applyMiddleware ,前者就是字面意思创建 Store,后者是应用组件,而thunk 就是确保之后的内容可以进行异步操作。
下面是Action 和 Reducer 层。action中的方法被暴露在Component 后,可通过设定方法的专属名称,来找到Reducer 中对应的 action.type ,随后对改方法中的属性进行操作。
Action:
export const addToCarts = (data)=>{
console.log(data)
return {
type: 'ADDTOCARTS',
payload:data
}
}
Reducer:
var initialState = {
counter : 1,
lists : [],
total :0
};
function counter(state = initialState ,action){
// 有且只有一棵状态数,状态是只读的,需要利用纯函数来进行状态的修改
switch(action.type){
case 'INCREASE':
return {...state,counter:state.counter+1};
case 'DECREASE':
return {...state,counter:state.counter-1};
case 'GETLISTS': // 获取列表,payload 负载
return {...state,lists:action.payload}
default:
return state;
}
}
export default counter;
那么下面最后一步是路由操作。这里由于移动端用的是 react Native ,所以在一开始判断loading 属性是否存在时,会先加载一个
render() {
if(this.state.loading){
return
}else{
return (
);
}
}
为了更清晰给出移动端项目的逻辑结构,给出下图。简单说来就是同 mapDispatchToProps 暴露方法,mapStateTopProps 暴露属性,通过connect 将属性与方法注入到组件中。
整个移动端做下来的感觉是,数据不完全通过reducer 、action 层获取,直接axios 获取json-server 中的数据也可以,除非当前页面涉及到多个模块的相互引用。当然在过程中还发现,如果要做轮播图,可以用 swiper ,但是要做线性渐变效果、瀑布流等效果,现有的 JS 编码开发环境还是达不到想要的效果。这里react Native 还有另外一种开发模式。就是 JS编码+原生代码 结合模式开发环境。环境安装及配置更为复杂 不仅需要了解React Native相关的编码规范 需要熟悉Android Studio/Xcode原生开发软件 需要了解Java/Objective-c/Swift原生开发程序。这之后在下一轮的学习计划中,会尝试与 Java 结合有进一步的尝试。