写文章的时候还是 1.0.x ,现在已经 3.x 了. 虽然主体 API 没改,但是细节的 API 增加了很多,甚至更简单的方案.
关注 Redux 很久了,一直在等稳定版,终于稳定版出来了 不过真的运行起来,比我之前估计的复杂度高太多了 这边可以看我用 CirruScript 写的代码... 虽然效果是不怎么样 https://github.com/jiyinyiyong/redux-in-cirru
大概梳理下这两天遇到的东西,为后面做准备
关于
关于 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-redux
要开始写 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/examples
combineStore 和绑定 props 要注意
Redux 原来给出的概念,听起来很简单的,Store 部分很像 Elm 大致就是 Model 部分设计成为一个不可变数据,然后渲染 然而实际情况好像要复杂一些,目前的 Store 当中的数据不是这样的 按照文档,一般会出现这样的写法 combineReducers http://rackt.github.io/redux/docs/basics/Reducers.html 注意是 ES6 的对象,省略了 property 的书写,实际上是个 Object 的定义:
import { combineReducers } from 'redux';
const todoApp = combineReducers({
visibilityFilter,todos
});
这个方案的问题就是,Store 的顶层数据,其实是用 Object 模拟的 包括后边绑定数据到组件上,也是用了其中的一些 trick 比如说有这样的代码,用来指明 store 传入的数据怎样绑定到组件上 https://github.com/rackt/redux/blob/master/examples/counter/containers/CounterApp.js
function mapStateToProps(state) {
return {
counter: state.counter
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(CounterActions,dispatch);
}
export default connect(mapStateToProps,mapDispatchToProps)(Counter);
现在 API 按说已经稳定,但是个写法还是导致结果稍微复杂了一些 按作者说,Splitting Reducers,化大为小,是管理 Store 比较好的办法 但我总觉得应该是从不可变数据本身去找,而不是增加一套写法 也许以后文档上或者教程上会说得明确一些,现在我还不明白
细节要注意区分一下,而且要按照代码跑一跑才行,我描述得不清楚 由于上边这个结构的原因,store 本身定义的方法,也许不方便直接用
Provider 的写法
关于把 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
Middlewares
中间件的概念我没看懂,只是大致抄了一遍代码尝试了一遍 思路是用高阶函数对 store 做了一些封装,插入了一些 Action 的操作 http://rackt.github.io/redux/docs/advanced/Middleware.html
DevTools
前面提到了 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 的,注意不要忘掉处理
纯函数 Reducer
我在写 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 的方案清晰,细节还期待更灵活一些 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|