Redux 思想
感想
近期一直在研究Redux,搞得一头雾水,上周看了很多文档,多数讲的是数据之间的传递和使用方法,感觉机械搬copy相关代码并无大用,万一遇到什么奇葩的项目,还是得另寻道路
上周搞了一直的redux,反复架构实验最后都没有得到太多有用的东西,跟着教程一步一步来,却没有搞明白他的核心思想到底是什么,一直到27号,找到了一些能够引起我注意的东西,也许不是redux最核心的思想,但值得肯定的是,他在某些React Project with redux 中确实起到了关键的作用
上周的周志一直没能好好写,也是通过这篇日志,算是给我的周志一个补充和安慰吧,问题还是在于redux到底是个什么东西,很早就听说redux是块硬骨头,如大家所说,确实难啃,而且目前看来,毫无味道,简单的总结一下我是如何去啃这块骨头的
总结
你可能不需要 Redux
首先明确一点,Redux 是一个有用的架构,但不是非用不可。事实上,大多数情况,你可以不用它,只用 React 就够了。
曾经有人说过这样一句话。
"如果你不知道是否需要 Redux,那就是不需要它。"
Redux 的创造者 Dan Abramov 又补充了一句。
"只有遇到 React 实在解决不了的问题,你才需要 Redux 。"
简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。
- 用户的使用方式非常简单
用户之间没有协作- 不需要与服务器大量交互,也没有使用 WebSocket
-视图层(View)只从单一来源获取数据
上面这些情况,都不需要使用 Redux。
- 用户的使用方式复杂
- 不同身份的用户有不同的使用方式(比如普通用户和管理员)
- 多个用户之间可以协作
- 与服务器大量交互,或者使用了WebSocket
- View要从多个来源获取数据
上面这些情况才是 Redux 的适用场景:多交互、多数据源。
从组件角度看,如果你的应用有以下场景,可以考虑使用 Redux。
- 某个组件的状态,需要共享
- 某个状态需要在任何地方都可以拿到
- 一个组件需要改变全局状态
- 一个组件需要改变另一个组件的状态
发生上面情况时,如果不使用 Redux 或者其他状态管理工具,不按照一定规律处理状态的读写,代码很快就会变成一团乱麻。你需要一种机制,可以在同一个地方查询状态、改变状态、传播状态的变化。
总之,不要把 Redux 当作万灵丹,如果你的应用没那么复杂,就没必要用它。另一方面,Redux 只是 Web 架构的一种解决方案,也可以选择其他方案。
设计思想
Redux 的设计思想很简单,就两句话。
(1)Web 应用是一个状态机,视图与状态是一一对应的。
(2)所有的状态,保存在一个对象里面。
React-Redux
Redux 的作者封装了一个 React 专用的库 React-Redux,本文主要介绍它。
这个库是可以选用的。实际项目中,你应该权衡一下,是直接使用 Redux,还是使用 React-Redux。后者虽然提供了便利,但是需要掌握额外的 API,并且要遵守它的组件拆分规范。
UI 组件
React-Redux 将所有组件分成两大类:UI 组件(presentational component)和容器组件(container component)。
UI 组件有以下几个特征。
- 只负责 UI 的呈现,不带有任何业务逻辑
- 没有状态(即不使用this.state这个变量)
- 所有数据都由参数(this.props)提供
- 不使用任何 Redux 的 API
下面就是一个 UI 组件的例子。
const Title =
value => <h1>{value}</h1>;
因为不含有状态,UI 组件又称为"纯组件",即它纯函数一样,纯粹由参数决定它的值。
容器组件
容器组件的特征恰恰相反。
- 负责管理数据和业务逻辑,不负责 UI 的呈现
- 带有内部状态
- 使用 Redux 的 API
总之,只要记住一句话就可以了:UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑。
你可能会问,如果一个组件既有 UI 又有业务逻辑,那怎么办?回答是,将它拆分成下面的结构:外面是一个容器组件,里面包了一个UI 组件。前者负责与外部的通信,将数据传给后者,由后者渲染出视图。
React-Redux 规定,所有的 UI 组件都由用户提供,容器组件则是由 React-Redux 自动生成。也就是说,用户负责视觉层,状态管理则是全部交给它。
connect()
React-Redux 提供connect
方法,用于从 UI 组件生成容器组件。connect
的意思,就是将这两种组件连起来。
import { connect } from 'react-redux'
const VisibleTodoList = connect()(TodoList);
上面代码中,TodoList
是 UI 组件,VisibleTodoList
就是由 React-Redux 通过connect
方法自动生成的容器组件。
但是,因为没有定义业务逻辑,上面这个容器组件毫无意义,只是 UI 组件的一个单纯的包装层。为了定义业务逻辑,需要给出下面两方面的信息。
(1)输入逻辑:外部的数据(即state对象)如何转换为 UI 组件的参数
(2)输出逻辑:用户发出的动作如何变为 Action 对象,从 UI 组件传出去。
mapStateToProps()
mapStateToProps
是一个函数。它的作用就是像它的名字那样,建立一个从(外部的)state
对象到(UI 组件的)props
对象的映射关系。
作为函数,mapStateToProps
执行后应该返回一个对象,里面的每一个键值对就是一个映射。
mapDispatchToProps()
mapDispatchToProps
是connect
函数的第二个参数,用来建立 UI 组件的参数到store.dispatch
方法的映射。也就是说,它定义了哪些用户的操作应该当作 Action
,传给 Store
。它可以是一个函数,也可以是一个对象。
如果mapDispatchToProps
是一个函数,会得到dispatch
和ownProps
(容器组件的props
对象)两个参数。
组件
connect
方法生成容器组件以后,需要让容器组件拿到state
对象,才能生成 UI 组件的参数。
一种解决方法是将state
对象作为参数,传入容器组件。但是,这样做比较麻烦,尤其是容器组件可能在很深的层级,一级级将state
传下去就很麻烦。
React-Redux 提供Provider
组件,可以让容器组件拿到state
。
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todoApp from './reducers'
import App from './components/App'
let store = createStore(todoApp);
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
参考文档
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
评论已关闭