写文章的时候仍是
1.0.x
, 如今已经3.x
了.
虽然主体 API 没改, 可是细节的 API 增长了不少, 甚至更简单的方案.html
关注 Redux 好久了, 一直在等稳定版, 终于稳定版出来了
不过真的运行起来, 比我以前估计的复杂度高太多了
这边能够看我用 CirruScript 写的代码... 虽然效果是不怎么样
https://github.com/jiyinyiyong/redux-in-cirrureact
大概梳理下这两天遇到的东西, 为后面作准备git
关于 Redux 我遇到的中文社区已经有两篇文章, 还行
https://ruby-china.org/topics/26944
http://segmentfault.com/a/1190000003033033
另外中文文档也有同窗在翻译, 速度飞快啊:
https://github.com/camsong/redux-in-chinese
其余大量关于 Redux 的资源, 在列表能找到, 热度很高的
https://github.com/xgrommx/awesome-reduxgithub
要开始写 Redux 的话, 其实文档是分布在三个仓库当中的:
https://github.com/gaearon/redux
https://github.com/gaearon/redux-devtools
https://github.com/rackt/react-redux
其中 redux-devtools 是调试工具, 也是一个 React 组件
这个组件须要在开发环境判断渲染, 同时避免发布到线上去
而 react-redux 则是对于 React 的绑定, 包含了一些工具函数编程
我了解得不大具体, 其中 react-devtools 文档并不齐全
甚至须要去源码当中看具体的例子才能把 Demo 跑起来:
https://github.com/gaearon/redux-devtools/blob/master/examples/counter/containers/App.js
而 Redux 具体的写法, 也少不了要去看源码的 example 才算能够
https://github.com/rackt/redux/tree/master/examplesredux
combineStore
和绑定 props
要注意Redux 原来给出的概念, 听起来很简单的, Store 部分很像 Elm
大体就是 Model 部分设计成为一个不可变数据, 而后渲染
然而实际状况好像要复杂一些, 目前的 Store 当中的数据不是这样的
按照文档, 通常会出现这样的写法 combineReducers
http://rackt.github.io/redux/docs/basics/Reducers.html
注意是 ES6 的对象, 省略了 property 的书写, 其实是个 Object 的定义:segmentfault
import { combineReducers } from 'redux'; const todoApp = combineReducers({ visibilityFilter, todos });
这个方案的问题就是, Store 的顶层数据, 实际上是用 Object 模拟的
包括后边绑定数据到组件上, 也是用了其中的一些 trick
好比说有这样的代码, 用来指明 store 传入的数据怎样绑定到组件上
https://github.com/rackt/redux/blob/master/examples/counter/containers/CounterApp.jsapi
function mapStateToProps(state) { return { counter: state.counter } } function mapDispatchToProps(dispatch) { return bindActionCreators(CounterActions, dispatch); } export default connect(mapStateToProps, mapDispatchToProps)(Counter);
如今 API 按说已经稳定, 可是个写法仍是致使结果稍微复杂了一些
按做者说, Splitting Reducers, 化大为小, 是管理 Store 比较好的办法
但我总以为应该是从不可变数据自己去找, 而不是增长一套写法
也许之后文档上或者教程上会说得明确一些, 如今我还不明白ruby
细节要注意区分一下, 并且要按照代码跑一跑才行, 我描述得不清楚
因为上边这个结构的缘由, store 自己定义的方法, 也许不方便直接用ide
关于把 Store 的数据传递到组件当中, Redux 提供了额外的绑定
结果也带出来了 Provider 组件, 接收属性, 还接收函数做为参数, 写法是:
https://github.com/rackt/redux/blob/master/examples/counter/containers/Root.js
注意, CounterApp
这边没写属性, 是经过签名提到的写法注入进去的
大体上是 mapStateToProps
函数, 具体细节恐怕须要看源码:
import { Provider } from 'react-redux'; export default class Root extends Component { render() { return ( <Provider store={store}> {() => <CounterApp />} </Provider> ); } }
而 Provider 的概念负责的事情彷佛也多了一些, 具体到文档上看
http://rackt.github.io/redux/docs/basics/UsageWithReact.html
实现一个最简单的 Redux 应用, 须要的代码:
https://github.com/jackielii/simplest-redux-example/blob/master/index.js
中间件的概念我没看懂, 只是大体抄了一遍代码尝试了一遍
思路是用高阶函数对 store 作了一些封装, 插入了一些 Action 的操做
http://rackt.github.io/redux/docs/advanced/Middleware.html
前面提到了 Devtools
是用 React 组件的方式提供的
没找到详细的文档, 具体的例子我查看代码的 examples 才知道的
https://github.com/gaearon/redux-devtools/blob/master/examples/counter/containers/App.js
export default class App extends Component { render() { return ( <div> <Provider store={store}> {() => <CounterApp />} </Provider> <DebugPanel top right bottom> <DevTools store={store} monitor={LogMonitor} /> </DebugPanel> </div> ); } }
做者说调试工具是能够定制的, 由于仅仅是 React 组件而已
我估计大概是 LogMonitor 组件能够本身定义的关系
显示同时工具以后, 查看数据默认当作 JSON 对象处理和显示的,
在调试工具当中查看不可变数据稍微要加上一些代码:
https://github.com/gaearon/redux-devtools/issues/51
let selectDevToolsState = (state = {}) => Immutable.fromJS(state).toJS(); <DebugPanel top right bottom key="debugPanel"> <DevTools store={store} select={selectDevToolsState} monitor={LogMonitor} /> </DebugPanel>
其中 state
变量有可能为 undefined
的, 注意不要忘掉处理
我在写 Demo 时候刚开始写了 shortid.generate()
生成 id, 遇到个 bug
缘由是这个生成 id 的函数是在 reducer 内部运行的,
彷佛因为 DevTools 的存在, reducer 会被调用不少次, id 被建立了不少次
这不奇怪, 由于 Time Travel Debugger 就是会从新运行 Action 的
因此我才反应过来, 建立 id 在 Haskell 里也是跟 IO 有关的反作用函数
随机数还有读取外部环境的状态, 属于反作用, 会破坏纯函数
这个代码是不该该在 reducer 当中的写的, id 就放 Action Creator 里去了
这个可能一看暗示了 FRP 那样的编程思路引出的一个更深入的问题
平时咱们说 MVC, Model 是整个数据的核心, Model 能够被改变
在 FP 当中, Model 是以变化数据的 Stream 模拟它随着时间的改变
而这里, Store 做为 Model 倒是因变量, 距离核心还隔着一步
数据的核心其实是 initialState, 以及 Action 造成的 Stream
而 Model 其实是经过 initialState 和 Actions 不断计算出来的
bindActionCreators
Redux 的例子当中, 处理 Action 是经过绑定到组件 props
来传递的
而不是我此前采用的, 直接用一个模块去调用的写法. 具体写法看这边:
https://github.com/rackt/redux/blob/master/docs/api/bindActionCreators.md
不清楚利弊. 我只是以为这样设计太复杂了一些
这篇文章算不上教程, 而是初步尝试 Redux 留下来的一些 Tips我以为你们关注 Redux 应该都是为的 Time Travel Debugger 的能力如今看来 Redux 带来过多概念, 给咱们项目跟进形成了门槛整体思路上 Redux 比 Facebook 的方案清晰, 细节还期待更灵活一些