[React] 13 - Redux: react-redux

Ref: Redux 入门教程(三):React-Redux 的用法html

 

组件拆分规范


使用 React-Redux,须要掌握额外的 API,而且要遵照它的组件拆分规范react

 

React-Redux 将全部组件分红两大类:git

  • UI 组件 负责 UI 的呈现,就是conponent。
  • 容器组件 负责管理数据和逻辑,就是container。

若是一个组件既有 UI 又有业务逻辑,那怎么办?github

将它拆分红下面的结构:redux

 * 外面是一个容器组件,    ----> 前者负责与外部的通讯,将数据传给后者  ----> 由 React-Redux 自动生成闭包

 * 里面包了一个UI 组件。      ----> 后者渲染出视图                                         ----> 由用户提供框架

 

 

 

connect函数


1、 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化函数

   

 

 

2、connect的两个参数

  • mapStateToProps

创建一个从 (外部的)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.  

 

 

  

Provider 组件


1、原理

connect方法生成容器组件之后,须要让容器组件拿到state对象,才能生成 UI 组件的参数。

一种解决方法是将state对象做为参数,传入容器组件。可是,这样作比较麻烦,尤为是容器组件可能在很深的层级,一级级将state传下去就很麻烦。

React-Redux 提供Provider组件,可让容器组件拿到state。其实就是在讲下图。

 

  

2、放在共享位置里

利用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') )

 

3、从共享位置获取

子组件就能够从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: redux/examples/counter/

Ref: bbandydd/serverless-client-s3   【看上去将来会有用】

--------------------------------------------------------------------------------------------

Ref: bbandydd/React_Startkit                              【代码讲解】

Ref: [線上讀書會] andy workshop 一天入魂 react-redux【五个小时~】

 

1、效果图

3

 

 

2、代码结构

  • Redux组件拆分

从 3:34:05 / 5:14:37 开始讲解代码。

 

  • container 和 component 的区别

 

container更新状态;从redux's state去取,与redux沟通。

component画面如何呈现 based on props,不用redux。

 

Jeff: 下图可见,number & increment放在了”外面“。

 

 

3、代码分析

  • Step 1. 从Panel开始

 ---> main.js中的标签<Panel />

 

[container/Panel.js]

 ---> Panel组件的具体实现。

 

 ---> 前者写起来简单些。

export default Panel;
import Panel from '../';

export const Number;
import {Number} from 'Panel';

 

  • Step 2. 组件分离

 

  • Step 3. 发送动做信号

 == 先提出一个疑点 ==

原始方式:状态的改变(onClick事件在panel里)

Redux方式:状态的改变要放在action中,也就是,onClick实则在this,props传来的action中。

 

== 建立动做 ==

视频讲解 - 4:01:40 / 5:14:37  

点击按键,触发action,只是发了一个信号。以下,发了一个INCREMENT signal.

[actions/counterAction.js]

 

  • Step 4. 接收动做信号

== 执行动做 ==

reducer中去验证,即:计算新状态(硬拷贝)。

状态 object + 负载 object ==> 新的 状态 object。

[reducers/counterReducer.js]

 

  • Step 5. 建立 store

== 合并动做 ==

建立 store,将总的reducer做为参数进行了”绑定“

[store/configureStore.js]

 

  • Step 6. 两种组件的链接

视频讲解 - 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)

 

  • Step 7. 容器直接得到 store

[main.js]

configureStore 就是 createStore() 的地方。

 

 

4、添加新功能

有了Redux框架,新功能的添加就成了体力活,这也是 Redux 框架的优点和迷人的地方。

 

  • 按钮UI组件添加

Btn里这个button set里,继续添加一个button。

 

  • 动做信号添加

注意:这里取代了dispatch(...)方法,为何能这样呢?详见Step 6。

 

  • 状态更新方法添加

 

  • 使用“按钮UI组件”处添加

在Panel.js中 (container) 添加对应的使用方式。

相关文章
相关标签/搜索