云端卫士实战录 React + Redux 前端项目实践

来源:互联网 发布:java类加载机制面试题 编辑:程序博客网 时间:2024/06/07 07:19
《实战录》导语

  本期分享人为云端卫士运营平台工程师张雨,将带来React + Redux 前端项目实践分享。

  一、为什么选择React

  首先,React是用来解决一个大型应用的数据变更问题。如果你的应用足够简单,比如数据不变更,那么用React的确没有必要,因为你还要浪费时间去生成虚拟DOM,而且不需要考虑状态的变化。

  其次,React能自动处理数据变更后的UI。这样的话,代码就很少会直接处理DOM,那代码绝大多数都会处理数据的变更。这样会很大程度上简化代码。

  二、实际项目中的运用

  实际项目开发中,需要对 ES6 和 JSX 代码的构建、调试、代理、打包部署等进行一系列工程化的需求,我们选择webpack作为构建工具,编译解析ES6和JSX我们采用babel。Webpack和React结合的强大之一就是,在修改了组件源码之后,不刷新页面就能把修改同步到页面上。这里需要用到两个库webpack-dev-server和react-hot-loader。

  因为React的每一次更新都是全局刷新的虚拟DOM机制,所以React组件的热替换可以成为通用的加载器,从而极大提高开发效率。

  下面介绍一些我们在实际项目中运用到的库。

  1、react-redux

  由于React只是MVC中的View层,我们需要搭配中间件使用。这里我们选择了Redux。React本身和Redux之间并没有之间的关联,我们借助react-redux这个库来做连接。react-redux提供了两个关键模块,provider和connect。connect真正意义上的连接了React和Redux。Redux的核心概念就是action、store和reducer,调用关系如下所示。

  store.dispatch(action) --> reducer(state, action) --> final state

  store:代表的是数据模型,内部维护了一个state变量,用例描述应用的状态。store有两个核心方法,分别是getState、dispatch。前者用来获取store的状态(state),后者用来修改store的状态。

  action:对行为(如用户行为)的抽象,在redux里是一个普通的js对象。redux对action的约定比较弱,除了一点,action必须有一个type字段来标识这个行为的类型。

  reducer:一个普通的函数,用来修改store的状态。传入两个参数 state、action。其中,state为当前的状态(可通过store.getState()获得),而action为当前触发的行为(通过store.dispatch(action)调用触发)。reducer(state, action) 返回的值,就是store最新的state值。映射到我们的React应用中,store中维护的state就是我们的app state,一个React组件作为View层,做两件事:render和响应用户操作。于是connect就是将store中的必要数据作为props传递给React组件来render,并包装action creator用于在响应用户操作时dispatch一个action。

  connect的API:

  mapStateToProps:一个函数,返回值表示的是需要merge进props的state, mapDispatchToProps:可以是一个函数,返回值表示的是需要merge仅props的actionCreators,这里的actionCreator应该是已经被包装了dispatch了的,这里我们使用redux的bindActionCreators函数。bindActionCreators把action creators转成拥有同名keys的对象,但使用dispatch把每个action creator包围起来,这样可以直接调用它们。

  2、redux-actions

  我们引用了一个redux-actions库,用来生成基本action type函数模板代码。它的handleAction可以简化reducers的写法,不用写那么多switch语句。

  3、react-router

  react-router是官方维护的唯一可选的路由库,它通过管理URL,实现组件的切换和状态的变化。使用时,路由器Router就是React的一个组件。Router组件本身只是一个容器,真正的路由要通过Route组件定义。Route组件定义了URL和组件的对应关系,可以同时使用多个组件。

  import { Router, Route, hashHistory } from 'react-router';render(( <Router history={hashHistory}> <Route path="/" component={Home}/> <Route path="*" component={NotFound}/> <Route path="/login" component={Login}/> </Router>), document.getElementById('app'));

  4、redux-saga

  我们使用redux-saga处理异步请求。redux-saga只在程序运行时被调用一次,在后台执行时监听store中被dispatch的action,继而决定对该action做什么样的处理。redux-saga提供了多种Effects用于处理各种任务,包括回调异步函数,启动一个后台任务,dispatch一个action等。

  import { takeLatest, takeEvery } from 'redux-saga';import { take, call } from 'redux-saga/effects'; import Api from '…';

  function* watchUser(action) { try { const store = yield call(Api.watchUser, action.payload); yield put({type: "GET_USER_SUCCESS", user: store}); } catch (e) { yield put({type: "GET_USER_ERROR", message: e.message}); } });}function* mySaga(){ yield takeLatest("GET_USER_SUCCESS", watchUser)}export default mySaga;

  5、Fetch

  请求后台接口,我们选择了Fetch。Fetch的主要优点有:①语法简单,更加语义化②基于标准Promise实现,支持async/await③同构方便,使用isomorphic-fetch。

  6、immutable

  Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。

  三、后记

  React天生的组件化使我们能够沉淀可重用、可维护、高性能的UI组件, 它的代码基本就是组件的组合,分而治之的方式让代码的可阅读性很高,容易理解。而基于Redux的架构,确定性的store很容易定位问题, 无论是新增业务还是修改bug都不再困难。并且React实现了Virtual DOM,效率和性能明显提高。

0 0
原创粉丝点击