Usage with React
文章目录

Redux: Usage with React

Installation

1
npm install --save react-redux

Some Conceptions

Presentational and container components

Presentational Component(下称PC)有这么几个特性:

  1. 是个Component
  2. 这个鬼Component仅仅渲染HTMl

PC不应该和Redux的Store进行任何交互

Container Components(下称CC)有这么几个特性:

  1. PC传递Props, 提供数据
  2. 提供一些action, 如果PC需要任何交互操作的话, 那么就应该调用CC里面全被你刷屏后天晚上我才要严肃的函数, 这个函数一般通过props传递给了PC

CC应该负责和Redux的各种Dispatcher

Connect with React

今天我确定哪些东西是PC, 然后确定哪些东西是CC
PC可以先写起来
CC的话redux推荐使用他们API里面的connect()函数来自动进行生成

connect

首先看一个例子:

1
2
3
4
5
6
7
8
import { connect } from 'react-redux'

const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)

export default VisibleTodoList

这是一个CC, 其中包含了一个PC: TodoList

在传统React App中, TodoList里面仅仅对传进去的props进行渲染
connect()函数做的事情是: 将State已经Dispatcher的一系列的处理结果转换成props并且传给TodoList

格式:

1
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])(components)

components对应的组件和Redux的store绑定, 并且需要提供几个重要函数. (见下文)

mapStateToProps

格式:

1
mapStateToProps(state, [ownProps]): stateProps (Function)

根据当前的state以及ownProps结果返回一个obj, 并且这个obj会被merge到props里面

  • 这个函数会跟redux注册, 类似于绑定, 一旦store里面的状态被更新, 那么这个函数将被调用
    • 如果不想在这个时候被监听, 那么直接传一个null或者undefined
  • 第二个参数就是对应组件自身的props
    • 另外当传递的第二个参数的时候, 如果组件自身的props被更新了, 这个函数也会被重新调用, 并且这个比较是一种浅层的比较

比如: Link是个component, 这个函数的返回值决定当前Link是否应该显示:

1
2
3
4
5
6
7
8
9
10
11
const mapStateToProps = (state, ownProps) => {
return {
active: ownProps.filter === state.visibilityFilter
}
}


const FilterLink = connect(
mapStateToProps,
mapDispatchToProps
)(Link)

mapDispatchToProps

这里面会将不同的Action的实现Dispatch()动作连接起来

格式:

1
mapDispatchToProps(dispatch, [ownProps]): dispatchProps (Object or Function)
  • 可以传函数或者是一个对象
    • 如果传一个对象, 那么里面每个 Key 应该对应一个Redux Action Creator
      • 即将最终无论如何都要返回一个 Action对象
    • 如果传的是一个单独的函数, 那么 dispatch 会被当做第一个参数
  • 如果没有提供这个值, 那么就会将 dispatch 直接用到这个 component 里面(也就是不干涉 dispatch 的细节)

比如下面, 我们给一个 LinkonClick 事件绑定一个 dispatch

FilterLink.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

const setVisibilityFilter = filter => ({
type: 'SET_VISIBILITY_FILTER',
filter
})

const mapDispatchToProps = (dispatch, ownProps) => ({
onClick: () => dispatch(setVisibilityFilter(ownProps.filter))
})

export default connect(
mapStateToProps,
mapDispatchToProps
)(Link)

然后在 Link 这个 CC 里面调用上方设定的这个 onClick方法:

Presentational Component

随后就可以在PC里面获得传进去的这两个参数里面的事件

比如上面放到FilterLink.js里面的Link.js可以这么写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from 'react'
import PropTypes from 'prop-types'

const Link = ({ active, onClick, children }) => (
<button
onClick={onClick}
disabled={active}
>
{children}
</button>
)

Link.propTypes = {
active: PropTypes.bool.isRequired,
children: PropTypes.node.isRequired,
onClick: PropTypes.func.isRequired
}

export default Link

上方active, onClick 都来自props里面的数据
children是这个component自身的子dom

Project Structure

推荐的项目架构:

粗体代表是文件夹

  • src
    • index.html
    • actions (各种Action的描述)
    • components (各种PC)
    • reducers (Reducer)
    • containers (各种CC)
  • public
  • 其他文件(package.json, readme.md等)

Procedure Summary

  1. 写定 Action

    • Action 是个 obj, 不是函数
    • 下方是个 Redux Action Creator, RAC 会根据不同条件返回一个 Action
      1
      2
      3
      4
      5
      export const selectDataType = () => {
      return {
      type: SELECT_DATATYPE
      }
      }
    • 甚至可以在 RAC 里面进行各种 延时请求 , 请求最终可以返回一个 Promise, 一连串处理最终只要能够返回一个 Obj 就行
  2. 准备Reducer
    上面返回的 Obj 会传到 reducer 那儿, reducer 会根据内容进行处理(一般是通过 type 字段进行区分)并且返回一个新的 State

    1
    2
    3
    4
    5
    6
    7
    8
    export const reducer = (state = { counter: 0 }, action) => {
    switch (action.type) {
    case REQUEST_DATA:
    return {
    counter: state.counter + 1
    }
    }
    }

    最终 Action 会传递到 Reducer 函数里面,并且如果有很多个 Reducer 函数,那么可以利用 CombineReducers() 来进行合并,这样之后的 Action 就会传递到所有被绑定的函数上面

  3. 使用 connect 绑定一些 Component
    需要准备 mapStateToProps() 并且最终返回一个 connect 的结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    const mapStateToProps = (state = {msg: 'Click Here', data: {}}) => {
    return {
    msg: state.msg,
    data: state.data,
    dataType: state.dataType
    }
    }

    class App extends Component {

    handlerClick = e => {
    const { dispatch } = this.props
    dispatch(requestData())
    }

    render() {
    }
    }

    export default connect(mapStateToProps)(App)
  4. 接下来就是 PC 的 Onclick 里面 dispatch 一些 Action

    1
    2
    3
    4
    handlerClick = e => {
    const { dispatch, selectedSubreddit } = this.props
    dispatch(requestData())
    }
  5. dispatch 之后的结果会自然地保存到 State, 然后再通过 mapStateToProps() 转换成 props, 然后传给 CC 或者 PC 用于处理