react技术栈全家桶(总结及感悟)

简介

react确实是一个神奇而优雅的框架。在从事react项目以前,一直是在作angular的,angular是一个全面和庞大的框架,在起初设计的时候什么都有,复杂程度也很高,因此用angular作项目基本上不须要其余的辅助库来配合。可是react项目真的是不同了,要是只会一个react的话,很难开发出需求的。由于react就只负责UI的渲染。javascript

这里是我开发react工程的一个模板,平时开发过程当中遇到的需求上面都有对应的实例,技术栈:react + react-router + react-redux + saga + reselector + webpack + ES6 + Typescript + sass点击这里访问css

作react项目须要掌握什么

react 功能单一用于UI渲染, redux 用来管理数据, react-router 用来管理路由, webpack 用来配置工程, ES6 让代码更加优雅, redux-saga 用来处理异步请求, reselect 缓存机制用来减小state改变带来的渲染压力,还有一些为了交互衍生出来的中间件 react-reduxreact-router-reduxreact-router-dom ,预处理器 SassLess 尽可能也掌握下。

react

前面有说过react只负责ui的渲染html

从V-dom出发

react最难能难得的就是虚拟dom的思想,这里有个贴切的比喻:把dom和JavaScript想象为各自的2个岛屿,中间有桥梁相连,可是桥上设有收费站,JavaScript去访问dom岛屿的次数越多,费用就越高。这就是一个js操做dom的过程,也许咱们常常听到或者看到说尽可能少的去操做dom,很耗性能。可是DOM 操做成本到底高在哪儿?,这边小总结下:前端

从输入uri到页面加载好是一个很漫长的过程,咱们就从html的解析开始提及。①解析HTML,开始构建DOM树;②解析CSS,生成CSS规则树;③合并DOM树和CSS规则树,生成render树;④布局render树(Layout/reflow),这时候负责元素尺寸大小,位置的计算,属于js中回流过程;⑤绘制render树(paint),绘制页面像素,属于重绘的过程;⑥浏览器会将各层的信息发送给GPU(图像处理器),GPU将各层合成(composite),显示在屏幕上。这是初始化渲染的过程,经过js操做DOM后,会引发 回流 和重绘,回流的成本很高,一个节点的回流会致使兄弟节点和子节点的回流,这样就一直在消耗GPU资源,因此才有了成本高的说法。java

咱们从操做dom的成本开始引入react,它创造了虚拟dom而且将它们储存起来,每当状态发生变化的时候就会创造新的虚拟节点和之前的进行对比,让变化的部分进行渲染。整个过程没有对dom进行获取和操做,只有等真正render时,才会去操做真实dom,从而引起页面的渲染。react

V-dom的缺点

ReactJS 使用虚拟 DOM 机制,让前端开发者为每一个组件提供一个 render 函数。render 函数把 props 和 state 转换成 ReactJS 的虚拟 DOM,而后 ReactJS 框架根据render 返回的虚拟 DOM 建立相同结构的真实 DOM。webpack

每当 state 更改时,ReactJS 框架从新调用 render 函数,获取新的虚拟 DOM 。而后,框架会比较上次生成的虚拟 DOM 和新的虚拟 DOM 有哪些差别,进而把差别应用到真实 DOM 上。git

这样作有两大缺点:es6

//每次 state 更改,render 函数都要生成完整的虚拟 DOM,哪怕 state 改动很小,
//render函数也会完整计算一遍。若是 render 函数很复杂,这个过程就会白白浪费不少计算资源。

//ReactJS 框架比较虚拟 DOM 差别的过程,既慢又容易出错。好比,你想要在某个 <ul> 列表的顶部插入一项 <li> ,
//那么 ReactJS 框架会误觉得你修改了 <ul> 的每一项 <li>,而后在尾部插入了一个 <li>。
复制代码

这是由于 ReactJS 收到的新旧两个虚拟 DOM 之间相互独立,ReactJS 并不知道数据源发生了什么操做,只能根据新旧两个虚拟 DOM 来猜想须要执行的操做。自动的猜想算法既不许又慢,必需要前端开发者手动提供 key 属性、shouldComponentUpdate 方法、componentDidUpdate 方法或者 componentWillUpdate 等方法才能帮助 ReactJS 框架猜对。github

diff算法

react的diff算法用在什么地方呢?当组件更新的时候,react会建立一个新的虚拟dom树而且会和以前储存的dom树进行比较,这个比较的过程就用到了diff算法,因此组件初始化的时候是用不到的。react提出了一种假设,相同的节点具备相似的结构,而不一样的节点具备不一样的结构。在这种假设之上进行逐层的比较,若是发现对应的节点是不一样的,那就直接删除旧的节点以及它所包含的全部子节点而后替换成新的节点。若是是相同的节点,则只进行属性的更改。

对于列表的diff算法稍有不一样,由于列表一般具备相同的结构,在对列表节点进行删除,插入,排序的时候,单个节点的总体操做远比一个个对比一个个替换要好得多,因此在建立列表的时候须要设置key值,这样react才能分清谁是谁。固然不写key值也能够,但这样一般会报出警告,通知咱们加上key值以提升react的性能。

须要深刻了解diff源码的请参考源码解析

单项数据流

组件化

组件就是拥有独立功能的视图模块,React的最大好处在于:功能组件化,遵照前端可维护的原则。

组件生命周期

组件初始化会触发的5个钩子函数

1.getDefaultProps()

设置默认的props,也能够用defaultProps设置组件的默认属性。

getDefaultProps至关于ES6中的 static defaultProps = {}

2.getInitialState()

在使用es6的class语法时是没有这个钩子函数的,能够直接在constructor中定义this.state。此时能够访问this.props。

getInitialState至关于ES6 class中constructor的 this.state = {}

钩子函数1 2 只有用React.createClass方法创造的组件类才会发生做用,而且React.createClass已经被Fb官方废弃,因此这里不细讲了。

3.componentWillMount()

组件初始化时只调用,之后组件更新不调用,整个生命周期只调用一次,此时能够修改state。

4.render()

react最重要的步骤,建立虚拟dom,进行diff算法,更新dom树都在此进行。

render() 应该是一个纯函数,彻底根据state和props来决定返回结果,而不产生反作用,因此render中调用setState是错的,由于纯函数不该该引发状态的改变

5.componentDidMount()

组件渲染以后调用,能够经过this.getDOMNode()获取和操做dom节点,只调用一次。

did的前缀表示进入状态以后调用,好比componentDidMount,组件通常初始化都会在这里进行数据请求。

为何请求数据要在这个钩子函数里面调用?

个人总结详见react中遇到的一些问题的解答

组件交互更新时触发的5个钩子函数

6.componentWillReceiveProps(nextProps)

组件初始化时不调用,组件接受新的props时调用。

开发过程当中通常是在这个钩子函数里面改变state,此方法中改变state不会二次渲染而是进行state合并。

7.shouldComponentUpdate(nextProps, nextState)

react性能优化很是重要的一环。组件接受新的state或者props时调用,咱们能够设置在此对比先后两个props和state是否相同,若是相同则返回false阻止更新,由于相同的属性状态必定会生成相同的dom树,这样就不须要创造新的dom树和旧的dom树进行diff算法对比,节省大量性能,尤为是在dom结构复杂的时候。不过调用this.forceUpdate会跳过此步骤。

8.componentWillUpdate(nextProps, nextState)

组件初始化时不调用,只有在组件将要更新时才调用。

千万不要在这个函数中调用this.setState()方法,会形成循环调用。

9.render()

同上render(),建立虚拟dom,进行diff算法,更新dom树都在此进行。

10.componentDidUpdate()

组件初始化时不调用,组件更新完成后调用,此时能够获取dom节点。

在componentDidUpdate后才能获取更新后的this.state。若是想获取组件默认的props,而且赋值给State ,就能够在这里修改,达到UI上的效果。

组件卸载时调用

10.componentWillUnmount()

组件将要卸载时调用,一些事件监听和定时器须要在此时清除,还有此组件store上面的值也能够对应的清楚。

componentWillUnmount执行重置全部相关参数。在该方法中调用setState不会触发render,由于全部的更新队列,更新状态都被重置为null。

//数据清楚须要写在reducer里面
this.props.clearPointData();

[CLEAR_POINT_DATA]: (state, action: Action<any>) => {
    return Object.assign({}, state, {
        selectedReadingList: {},
        knowledgePoint: {},
    });
}
复制代码

以上能够看出来react总共有10个周期函数(render重复一次),这个10个函数能够知足咱们全部对组件操做的需求,利用的好能够提升开发效率和组件性能。

react-router

Router就是React的一个组件,它并不会被渲染,只是一个建立内部路由规则的配置对象,根据匹配的路由地址展示相应的组件。Route则对路由地址和组件进行绑定,Route具备嵌套功能,表示路由地址的包涵关系,这和组件之间的嵌套并无直接联系。Route能够向绑定的组件传递7个属性:children,history,location,params,route,routeParams,routes,每一个属性都包涵路由的相关的信息。比较经常使用的有children(以路由的包涵关系为区分的组件),location(包括地址,参数,地址切换方式,key值,hash值)。react-router提供Link标签,这只是对a标签的封装,值得注意的是,点击连接进行的跳转并非默认的方式,react-router阻止了a标签的默认行为并用pushState进行hash值的转变。切换页面的过程是在点击Link标签或者后退前进按钮时,会先发生url地址的转变,Router监听到地址的改变根据Route的path属性匹配到对应的组件,将state值改为对应的组件并调用setState触发render函数从新渲染dom。

当页面比较多时,项目就会变得愈来愈大,尤为对于单页面应用来讲,初次渲染的速度就会很慢,这时候就须要按需加载,只有切换到页面的时候才去加载对应的js文件。react配合webpack进行按需加载的方法很简单,Route的component改成getComponent,组件用require.ensure的方式获取,并在webpack中配置chunkFilename。

const chooseProducts = (location, cb) => {
    require.ensure([], require => {
        cb(null, require('../Component/chooseProducts').default)
    },'chooseProducts')
}

const helpCenter = (location, cb) => {
    require.ensure([], require => {
        cb(null, require('../Component/helpCenter').default)
    },'helpCenter')
}

const saleRecord = (location, cb) => {
    require.ensure([], require => {
        cb(null, require('../Component/saleRecord').default)
    },'saleRecord')
}

const RouteConfig = (
    <Router history={history}>
        <Route path="/" component={Roots}>
            <IndexRoute component={index} />//首页
            <Route path="index" component={index} />
            <Route path="helpCenter" getComponent={helpCenter} />//帮助中心
            <Route path="saleRecord" getComponent={saleRecord} />//销售记录
            <Redirect from='*' to='/'  />
        </Route>
    </Router>
);
复制代码

react-router-redux

保持路由与应用状态(state)同步。使用redux管理应用状态(state),使用router管理路由,两个库不能协同工做,react-router-redux库能够协调这两个库。

react-router-dom

...

redux

组件间的通讯

react推崇的是单向数据流,自上而下进行数据的传递,可是由下而上或者不在一条数据流上的组件之间的通讯就会变的复杂。解决通讯问题的方法不少,若是只是父子级关系,父级能够将一个回调函数看成属性传递给子级,子级能够直接调用函数从而和父级通讯。

组件层级嵌套到比较深,可使用上下文getChildContext来传递信息,这样在不须要将函数一层层往下传,任何一层的子级均可以经过this.context直接访问。

兄弟关系的组件之间没法直接通讯,它们只能利用同一层的上级做为中转站。而若是兄弟组件都是最高层的组件,为了可以让它们进行通讯,必须在它们外层再套一层组件,这个外层的组件起着保存数据,传递信息的做用,这其实就是redux所作的事情。

组件之间的信息还能够经过全局事件来传递。不一样页面能够经过参数传递数据,下个页面能够用location.param来获取。其实react自己很简单,难的在于如何优雅高效的实现组件之间数据的交流。

redux

首先,redux并非必须的,它的做用至关于在顶层组件之上又加了一个组件,做用是进行逻辑运算、储存数据和实现组件尤为是顶层组件的通讯。若是组件之间的交流很少,逻辑不复杂,只是单纯的进行视图的渲染,这时候用回调,context就行,不必用redux,用了反而影响开发速度。可是若是组件交流特别频繁,逻辑很复杂,那redux的优点就特别明显了。我第一次作react项目的时候并无用redux,全部的逻辑都是在组件内部实现,当时为了实现一个逻辑比较复杂的购物车,洋洋洒洒竟然写了800多行代码,回头一看我本身都不知道写的是啥,画面太感人。

先简单说一下redux和react是怎么配合的。react-redux提供了connect和Provider两个好基友,它们一个将组件与redux关联起来,一个将store传给组件。组件经过dispatch发出action,store根据action的type属性调用对应的reducer并传入state和这个action,reducer对state进行处理并返回一个新的state放入store,connect监听到store发生变化,调用setState更新组件,此时组件的props也就跟着变化。

流程是这个样子的:

值得注意的是connect,Provider,mapStateToProps,mapDispatchToProps是react-redux提供的,redux自己和react没有半毛钱关系,它只是数据处理中心,没有和react产生任何耦合,是react-redux让它们联系在一块儿。

接下来具体分析一下,redux以及react-redux究竟是怎么实现的。

先上一张图

明显比第一张要复杂,其实两张图说的是同一件事。从上而下慢慢分析:

先说说redux

redux主要由三部分组成:store,reducer,action。

store是一个对象,它有四个主要的方法:

一、dispatch:

用于action的分发----在createStore中能够用middleware中间件对dispatch进行改造,好比当action传入dispatch会当即触发reducer,有些时候咱们不但愿它当即触发,而是等待异步操做完成以后再触发,这时候用redux-thunk对dispatch进行改造,之前只能传入一个对象,改造完成后能够传入一个函数,在这个函数里咱们手动dispatch一个action对象,这个过程是可控的,就实现了异步。

二、subscribe:

监听state的变化----这个函数在store调用dispatch时会注册一个listener监听state变化,当咱们须要知道state是否变化时能够调用,它返回一个函数,调用这个返回的函数能够注销监听。 let unsubscribe = store.subscribe(() => {console.log('state发生了变化')})

三、getState:

获取store中的state----当咱们用action触发reducer改变了state时,须要再拿到新的state里的数据,毕竟数据才是咱们想要的。getState主要在两个地方须要用到,一是在dispatch拿到action后store须要用它来获取state里的数据,并把这个数据传给reducer,这个过程是自动执行的,二是在咱们利用subscribe监听到state发生变化后调用它来获取新的state数据,若是作到这一步,说明咱们已经成功了。

四、replaceReducer:

替换reducer,改变state修改的逻辑。

action:

action是一个对象,其中type属性是必须的,同时能够传入一些数据。action能够用actionCreactor进行创造。dispatch就是把action对象发送出去。

reducer:

reducer是一个函数,它接受一个state和一个action,根据action的type返回一个新的state。根据业务逻辑能够分为不少个reducer,而后经过combineReducers将它们合并,state树中有不少对象,每一个state对象对应一个reducer,state对象的名字能够在合并时定义。

像这个样子:

const reducer = combineReducers({
     a: doSomethingWithA,
     b: processB,
     c: c
})
复制代码

combineReducers:

其实它也是一个reducer,它接受整个state和一个action,而后将整个state拆分发送给对应的reducer进行处理,全部的reducer会收到相同的action,不过它们会根据action的type进行判断,有这个type就进行处理而后返回新的state,没有就返回默认值,而后这些分散的state又会整合在一块儿返回一个新的state树。

接下来分析一下总体的流程,首先调用store.dispatch将action做为参数传入,同时用getState获取当前的状态树state并注册subscribe的listener监听state变化,再调用combineReducers并将获取的state和action传入。combineReducers会将传入的state和action传给全部reducer,并根据action的type返回新的state,触发state树的更新,咱们调用subscribe监听到state发生变化后用getState获取新的state数据。

redux的state和react的state二者彻底没有关系,除了名字同样。

上面分析了redux的主要功能,那么react-redux到底作了什么?

react-redux

若是只使用redux,那么流程是这样的:

component --> dispatch(action) --> reducer --> subscribe --> getState --> component

用了react-redux以后流程是这样的:

component --> actionCreator(data) --> reducer --> component

store的三大功能:dispatch,subscribe,getState都不须要手动来写了。react-redux帮咱们作了这些,同时它提供了两个好基友Provider和connect。

Provider是一个组件,它接受store做为props,而后经过context往下传,这样react中任何组件均可以经过context获取store。也就意味着咱们能够在任何一个组件里利用dispatch(action)来触发reducer改变state,并用subscribe监听state的变化,而后用getState获取变化后的值。可是并不推荐这样作,它会让数据流变的混乱,过分的耦合也会影响组件的复用,维护起来也更麻烦。

connect --connect(mapStateToProps, mapDispatchToProps, mergeProps, options) 是一个函数,它接受四个参数而且再返回一个函数--wrapWithConnect,wrapWithConnect接受一个组件做为参数wrapWithConnect(component),它内部定义一个新组件Connect(容器组件)并将传入的组件(ui组件)做为Connect的子组件而后return出去。

因此它的完整写法是这样的:connect(mapStateToProps, mapDispatchToProps, mergeProps, options)(component)

mapStateToProps(state, [ownProps]):

mapStateToProps 接受两个参数,store的state和自定义的props,并返回一个新的对象,这个对象会做为props的一部分传入ui组件。咱们能够根据组件所须要的数据自定义返回一个对象。ownProps的变化也会触发mapStateToProps

function mapStateToProps(state) {
   return { todos: state.todos };
}
复制代码

mapDispatchToProps(dispatch, [ownProps]):

mapDispatchToProps若是是对象,那么会和store绑定做为props的一部分传入ui组件。若是是个函数,它接受两个参数,bindActionCreators会将action和dispatch绑定并返回一个对象,这个对象会和ownProps一块儿做为props的一部分传入ui组件。因此不论mapDispatchToProps是对象仍是函数,它最终都会返回一个对象,若是是函数,这个对象的key值是能够自定义的

function mapDispatchToProps(dispatch) {
   return {
      todoActions: bindActionCreators(todoActionCreators, dispatch),
      counterActions: bindActionCreators(counterActionCreators, dispatch)
   };
}
复制代码

mapDispatchToProps返回的对象其属性其实就是一个个actionCreator,由于已经和dispatch绑定,因此当调用actionCreator时会当即发送action,而不用手动dispatch。ownProps的变化也会触发mapDispatchToProps。

mergeProps(stateProps, dispatchProps, ownProps):

将mapStateToProps() 与 mapDispatchToProps()返回的对象和组件自身的props合并成新的props并传入组件。默认返回 Object.assign({}, ownProps, stateProps, dispatchProps) 的结果。

options:

pure = true 表示Connect容器组件将在shouldComponentUpdate中对store的state和ownProps进行浅对比,判断是否发生变化,优化性能。为false则不对比。

其实connect函数并无作什么,大部分的逻辑都是在它返回的wrapWithConnect函数内实现的,确切的说是在wrapWithConnect内定义的Connect组件里实现的。

下面是一个完整的 react --> redux --> react 流程:

1、Provider组件接受redux的store做为props,而后经过context往下传。

2、connect函数在初始化的时候会将mapDispatchToProps对象绑定到store,若是mapDispatchToProps是函数则在Connect组件得到store后,根据传入的store.dispatch和action经过bindActionCreators进行绑定,再将返回的对象绑定到store,connect函数会返回一个wrapWithConnect函数,同时wrapWithConnect会被调用且传入一个ui组件,wrapWithConnect内部使用class Connect extends Component定义了一个Connect组件,传入的ui组件就是Connect的子组件,而后Connect组件会经过context得到store,并经过store.getState得到完整的state对象,将state传入mapStateToProps返回stateProps对象、mapDispatchToProps对象或mapDispatchToProps函数会返回一个dispatchProps对象,stateProps、dispatchProps以及Connect组件的props三者经过Object.assign(),或者mergeProps合并为props传入ui组件。而后在ComponentDidMount中调用store.subscribe,注册了一个回调函数handleChange监听state的变化。

3、此时ui组件就能够在props中找到actionCreator,当咱们调用actionCreator时会自动调用dispatch,在dispatch中会调用getState获取整个state,同时注册一个listener监听state的变化,store将得到的state和action传给combineReducers,combineReducers会将state依据state的key值分别传给子reducer,并将action传给所有子reducer,reducer会被依次执行进行action.type的判断,若是有则返回一个新的state,若是没有则返回默认。combineReducers再次将子reducer返回的单个state进行合并成一个新的完整的state。此时state发生了变化。dispatch在state返回新的值以后会调用全部注册的listener函数其中包括handleChange函数,handleChange函数内部首先调用getState获取新的state值并对新旧两个state进行浅对比,若是相同直接return,若是不一样则调用mapStateToProps获取stateProps并将新旧两个stateProps进行浅对比,若是相同,直接return结束,不进行后续操做。若是不相同则调用this.setState()触发Connect组件的更新,传入ui组件,触发ui组件的更新,此时ui组件得到新的props,react --> redux --> react 的一次流程结束。

上面的有点复杂,简化版的流程是:

1、Provider组件接受redux的store做为props,而后经过context往下传。

2、connect函数收到Provider传出的store,而后接受三个参数mapStateToProps,mapDispatchToProps和组件,并将state和actionCreator以props传入组件,这时组件就能够调用actionCreator函数来触发reducer函数返回新的state,connect监听到state变化调用setState更新组件并将新的state传入组件。

connect能够写的很是简洁,mapStateToProps,mapDispatchToProps只不过是传入的回调函数,connect函数在必要的时候会调用它们,名字不是固定的,甚至能够不写名字。

简化版本:

connect(state => state, action)(Component);
复制代码

redux-saga

有待更新。。。

reselect

在React中最昂贵的操做就是渲染回路.当组件检测到输入的变化,渲染回路就会被触发(译注:这里的意思的组件的action会改变redux的state,变回最终又回到组件了).

当咱们初次开始React程序的时候,咱们不会担忧渲染回路的花销问题.可是当咱们的UI变得复杂的时候,咱们须要考虑这一点.React提供了一些工具让咱们能劫持渲染回路,若是渲染看上去没必要要,咱们就可使用工具来阻止重渲染的发生.为了这么作,咱们要敲入componentShouldUpdate生命周期事件,返回一个布尔值,通知组件是否应该进行更新.这是以PureRenderMixin做为基础,它比较输入的props和state和先前的props和state,若是二者相等就返回false.

不幸的是,仅此而已.

Reselect用来记忆selectors的库.咱们定义的selectors是做为函数获取Redux state的某一部分.使用记忆能力,咱们能够组织没必要要的衍生数据的重渲染和计算过程,由此加速了咱们的app.

Reselect这个中间件要解决的问题是:在组件交互操做的时候,state发生变化的时候如何减小渲染的压力.在Reselect中间中使用了缓存机制

"selector"是一个简单的Redux库

  • Selector能够计算衍生的数据,可让Redux作到存储尽量少的state。
  • Selector比较高效,只有在某个参数发生变化的时候才发生计算过程.
  • Selector是能够组合的,他们能够做为输入,传递到其余的selector.

参考

-使用Reselect改进React和Redux程序性能

ES6

在react工程当中,ES6/7/8处处可见,因此ES6也必需要掌握,由于内容太多就简单总结下经常使用的一些技巧。具体的可参考 阮一峰老师的ES6入门

其实ES6相对于ES5来讲,新增了不少的东西,列举些经常使用的:使用let const彻底抛弃var;模板的导入导出(import,export);字符串的扩展(``,${});对象的扩展(结构赋值,新增了一些api如assgin(),keys(),is()等;数组的扩展(结构赋值,from(),of(),findIndex(),find()等);函数的扩展(函数参数能够设置默认值,箭头函数,没有arguments对象等);经常使用来遍历的(for of,forEach,for in,map等);用于解决异步的(generator函数,promise,async/await函数等);class和extends关键字等

虽然不少ES6的技巧用ES5一样能实现,可是ES6大大提升了开发效率,代码也更加优雅,何况各种的打包工具均可以将ES6转化成适配低浏览器的ES5,因此推荐你们使用。

webpack

参考webpack官网

Sass or Less

随着前端的不断发展,网站的页面复杂度也在不断提高,原生 CSS 已经让开发者力不从心,预处理器赋予咱们的 "超能力"。浅谈 CSS 预处理器:为何要使用预处理器?

Sass

参考Sass语法

Less

参考Less语法

===================================end==================================

React Prepare

最后附上react技术栈的相关连接,但愿对你们有帮助!

react

React 入门实例教程

React 技术栈系列教程

react 组件

React建立组件的三种方式及其区别

从性能角度看react组件拆分的重要性

react 性能篇

React性能优化总结

现代 Web 开发--React 篇

React.js 初学者应该知道的9件事

react router

React Router 使用教程

redux

Redux 入门教程(一):基本用法

Redux 入门教程(二):中间件与异步操做

Redux 入门教程(三):React-Redux 的用法

Redux 中文文档

Redux 英文文档

Redux 核心概念

React 实践心得:react-redux 之 connect 方法详解

redux-saga/redux-thunk

saga 中文文档

聊一聊 redux 异步流之 redux-saga

Redux-Saga 实用指北

Reselect

Others

Flux 架构入门教程

Immutable

dom diff

Generator 函数的含义与用法

相关文章
相关标签/搜索