Ref: Redux 入门教程(三):React-Redux 的用法html
使用 React-Redux,须要掌握额外的 API,而且要遵照它的组件拆分规范。react
React-Redux 将全部组件分红两大类:git
若是一个组件既有 UI 又有业务逻辑,那怎么办?github
将它拆分红下面的结构:redux
* 外面是一个容器组件, ----> 前者负责与外部的通讯,将数据传给后者 ----> 由 React-Redux 自动生成闭包
* 里面包了一个UI 组件。 ----> 后者渲染出视图 ----> 由用户提供框架
connect
方法,用于从 UI 组件生成容器组件。connect
的意思,就是将这两种组件连起来。less
import { connect } from 'react-redux'
const VisibleTodoList【容器组件】 = connect(mapStateToProps, mapDispatchToProps)(TodoList【UI组件】)
(1) 一个页面可能会有十个state,使用connect让咱们只关注当前有使用的几个。ide
(2) 尾部的参数的意思:由于返回的是一个带参数的func,参见: js 用闭包实现 curry化函数
创建一个从 (外部的)state
对象 到(UI 组件的)props
对象 的映射关系。
state
对象/**
* 参数state表明的是 整个网页的“状态”。
*/
const mapStateToProps = (state) => {
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter) // 从算出 的值 ---->
}
}statetodos
从state
算出 todos
的值。
const getVisibleTodos = (todos, filter) => {
switch (filter) {
case 'SHOW_ALL':
return todos
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed)
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed)
default:
throw new Error('Unknown filter: ' + filter)
}
}
props
对象// 容器组件的代码 // <FilterLink filter="SHOW_ALL"> // All // </FilterLink> const mapStateToProps = (state, ownProps) => { return { active: ownProps.filter === state.visibilityFilter } }
使用ownProps
做为参数后,若是容器组件的参数发生变化,也会引起 UI 组件从新渲染。
connect
方法能够省略mapStateToProps
参数,那样的话,UI 组件就不会订阅Store,就是说 Store 的更新不会引发 UI 组件的更新。
mapDispatchToProps
创建映射:(外部的)
state
对象 ====> (UI 组件的)props
对象创建映射:UI 组件的参数 ====>
store.dispatch
方法
定义了哪些用户的操做应该看成 Action,传给 Store。
const mapDispatchToProps = (
dispatch,
ownProps
) => {
return {
onClick: () => {
dispatch({
type: 'SET_VISIBILITY_FILTER',
filter: ownProps.filter
});
}
};
}
思考题:有了connect -> react-reduct,就不须要:Every listener registered with store.subscribe(listener) will now be invoked.
connect
方法生成容器组件之后,须要让容器组件拿到state
对象,才能生成 UI 组件的参数。
一种解决方法是将state
对象做为参数,传入容器组件。可是,这样作比较麻烦,尤为是容器组件可能在很深的层级,一级级将state
传下去就很麻烦。
React-Redux 提供Provider
组件,可让容器组件拿到state
。其实就是在讲下图。
利用React
组件的context
属性,Provider
在根组件外面包了一层,这样一来,App
的全部子组件就默认均可以拿到state
了。
import { Provider } from 'react-redux' import { createStore } from 'redux' import todoApp from './reducers' import App from './components/App' let store = createStore(todoApp); render(
<Providerstore={store}> // <----------- 这里就是重点! <App /> </Provider>,
document.getElementById('root') )
子组件就能够从context
拿到store
/* 容器组件,visibleTodoList */
class VisibleTodoList extends Component {
componentDidMount() {
const { store } = this.context;
this.unsubscribe = store.subscribe(() =>
this.forceUpdate()
);
}
render() {
const props = this.props;
const { store } = this.context;
const state = store.getState();
// ...
}
}
VisibleTodoList.contextTypes = {
store: React.PropTypes.object
}
Ref: jackielii/simplest-redux-example
Ref: bbandydd/serverless-client-s3 【看上去将来会有用】
--------------------------------------------------------------------------------------------
Ref: bbandydd/React_Startkit 【代码讲解】
Ref: [線上讀書會] andy workshop 一天入魂 react-redux【五个小时~】
3
从 3:34:05 / 5:14:37 开始讲解代码。
container:更新状态;从redux's state去取,与redux沟通。
component:画面如何呈现 based on props,不用redux。
Jeff: 下图可见,number & increment放在了”外面“。
---> main.js中的标签<Panel />
[container/Panel.js]
---> Panel组件的具体实现。
---> 前者写起来简单些。
export default Panel;
import Panel from '../';
export const Number;
import {Number} from 'Panel';
== 先提出一个疑点 ==
原始方式:状态的改变(onClick事件在panel里)
Redux方式:状态的改变要放在action中,也就是,onClick实则在this,props传来的action中。
== 建立动做 ==
视频讲解 - 4:01:40 / 5:14:37
点击按键,触发action,只是发了一个信号。以下,发了一个INCREMENT signal.
[actions/counterAction.js]
== 执行动做 ==
去reducer中去验证,即:计算新状态(硬拷贝)。
状态 object + 负载 object ==> 新的 状态 object。
[reducers/counterReducer.js]
== 合并动做 ==
建立 store,将总的reducer做为参数进行了”绑定“。
[store/configureStore.js]
视频讲解 - 4:30:46 / 5:14:37
若有没有这个参数,全部的state就所有给了Panel(contrainer角色)处理;
有这两个参数,就是”只处理“当前用到的。
export default connect(mapStateToProps, mapDispatchToProps)(Panel);
解决什么问题?
下图 line 17 为什么能方便地直接获取 ”当下所需“ 的变量,这即是 connect 的功劳。
== 第一个参数 ==
line 31, 表示全部的state。return的就是其中须要用到的。
== 第二个参数 ==
line 39,至关于替代了 dispatch(counterAction)。
[main.js]
configureStore 就是 createStore() 的地方。
有了Redux框架,新功能的添加就成了体力活,这也是 Redux 框架的优点和迷人的地方。
Btn里这个button set里,继续添加一个button。
注意:这里取代了dispatch(...)方法,为何能这样呢?详见Step 6。
在Panel.js中 (container) 添加对应的使用方式。