听说你需要这样了解 Redux(二)
rccoder opened this issue · 1 comments
1. 前言
很久很久之前,写过一篇介绍 Redux 相关概念的文章 听说你需要这样了解 Redux(一),随后因为实习的事情拖延了后续(根本原因是懒)。
在实习中也更加深刻的认识了 Redux 相关的内容。除此之外,翻译 Redux 中文文档 redux-in-chinese 也让我静心下来仔细品读了设计理念。
这篇文章中我将介绍一个如何把 React 和 Redux 这两个大杀器结合起来,同时也会介绍一些 state、reducer 设计相关的东西。
2. 正文
2.1 连接神器 react-redux
react 和 redux 可以说是没有任何关系,redux 主要提供一个全局的 store,然后 react 从 store 拿去数据,store 发生变化,react 重新进行渲染。
在远古时代我们就已经知道频繁操作 DOM 是很耗费性能的,react 在数据发生变化的时候就会进行 render,虽然我们可以用 PureRenderMixin 或者在 shouldComponentUpdate 做一些处理,但对于一个页面的数据来说,这好像也是非常麻烦的。
react-redux 的出现就解决了这个问题,并且保证了整个应用程序的灵活性与可维护性。用官方的话说就是:
Performant and flexible
react-redux 提供了两个耳熟能详的 API: <Provider store>
和 connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
。
在上篇文章中已经简单介绍过这两个 API 的基础概念:
Provider 是在原有的 APP 上面包一层,然后接收 store 作为 props,然后给 connect 用
connect 接收 store 提供的 state 和 action,返回给我们的 react 组件;还有一个很重要的一点是在 connect 这层 react-redux 做了优化,保证给组件只传和他相关的 state,这也就保证了性能上的优势
2.2 搭个架子
//index.jsx
import { ReactDOM } from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.querySelector('#app')
);
// App.jsx
import { React } from 'react';
import { connect } from 'react-redux';
class App extends Component {
render() {
<div>Test<div>
}
}
export default connect(state => state, actions)(App);
这里 connect
只传递了两个参数 state => state
、actions
。
state => state
就是 mapStateToProps
的函数,他会监听 store 的变化,只要 store 变化,这个函数就会被调用。mapStateToProps
返回一个对象,这个对象会与组件的 props 合并。mapStateToProps
接收两个参数 state
、ownProps
,通常情况下我们只需要第一个参数,如果有第二个参数 ownProps
,其也将传给组件的 props,并且当组件的 props 发生变化时也会调用 mapStateToProps
。这个例子中进去与返回的都是 state
,这在实际开发中是不科学的,为了保证我们应用的性能,我们应该只返回需要的 state 切片。
action
就是 mapDispatchToProps
,他可以是个函数,也可以是个对象。如果是个函数,这个函数将接收一个 dispatch
函数,然后由我们决定返回怎样的一个对象,这个对象会通过 dispatch
函数与 action creator 绑定起来;如果是个对象,则这个对象中的函数都会被当做 action creator,而且这个对象会与 store 绑定在一起,其中所定义的方法名将作为属性名,合并到组件的 props 中。一般情况下会省略这个参数。
mergeProps
用于自定义 props 合并,默认返回 Object.assign({}, ownProps, stateProps, dispatchProps)
。
options
是一个优化开关,这里不做太多解释(我还没用过啊!)。
关于 connect
详细的说明,还是建议阅读官方文档:https://github.com/reactjs/react-redux/blob/master/docs/api.md
这里有个小聪明可以玩,如果你已经用上了 babel 全家桶并且是一个激进的人,可以用装饰器优雅的写 connect:
@connect(state => state, actions)
export default class App extends Component {
render() {
<div>Test<div>
}
}
2.3 store 绑定
从用 React 的第一天起,“单向数据流” 的概念就已经扎进了心口。在上面的例子中,我们可以看到一个简单清晰的流向:
从 store -> connect 层做处理 -> 组件 props
那在实际的交互中,又是如何的往 store 中塞入数据的呢?这个就和 Redux 连接起来了。
import {createStore, applyMiddleware, compose} from "redux";
import thunkMiddleware from "redux-thunk";
const rootReducer = (state, action) => {
let result = state;
switch(action.type) {
case "TYPE_A":
// 省略
break;
default:
break;
}
return result;
}
const initialState = {};
const middleware = [thunkMiddleware];
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware),
window.devToolsExtension ? window.devToolsExtension() : f => f
)
)
和上章节中一样,用 Redux 提供的 createStore
创建 Redux store,然后把 store 在 Redux 提供的 Provider 中传递进去。
同样,通过 store.dispatch({type: 'xx', text: 'xx'})
就能融入整个 Redux 中。每当 store 发生变化,react-redux 就会处理 subscribe
与 getState
,传给相应的组件,同时也保持了比较高的性能。
2.4 state、reducer 设计
参考我翻译的 redux 文档:State 范式化、管理范式化数据
里面有详细的说明,并且有很不错的例子。更应该的,你应该详细阅读一下所有文档,尤其是 组织 Reducer 这块。
参考资料
系列文章
EOF