React 全家桶之 react-redux

在谈 react-redux 之前,我们先来回顾一下 react 组件的通信方式:

  1. 通过 props 父传子,子传孙。缺点是层级较深的话,传递会比较麻烦。消息横向传递很麻烦。
  2. 消息订阅发布模式,需要自己实现监听和触发这一过程。消息可以同级横向传递,如 A 和 B 都是 C 的子组件,可以在 C 组件中调度 A、B 的监听函数。
  3. 通过 react 中的上下文对象 context 来传递消息,由于 context 全局独一份,所以可以实现跨层级、横向的消息传递

我们来看一下第三种方式,context 的使用姿势

class Man extends React.Component {
  getChildrenContext () {
    return {
      num: 100
    }
  }
  render () {
    <div>
      <Son>
        <Grandson></Grandson>
      </Son>
    </div>
  }
}

Man.childContextTypes = {
  num: React.Prototypes.number
}
class Grandson extends React.Component {
  render () {
    return (
    <div>{ this.context.num }</div>
    )
  }
}
Grandson.contextTypes = {
  num: React.Prototypes.number
}

可以看到 Man 组件中的 num 是可以跨层级传递给孙子组件 Grandson 的,而 react-redux 正是利用了这一点,基于 context 实现了数据的共享。

话不多说,先上代码,看一下 react-redux 怎么用,还是以上一篇文章【前端架构系列—React 全家桶之 redux】中的代码为例。reducer 和 store 都不用变,只是 component 改一下就行了。

这也好理解,reducer 和 store 是纯 redux 的部分,而 react-redux 是 react 和 redux 之间桥梁,所以要引入 react-redux,只要在原先 react 中实接使用 redux 的地方动动刀子就行了。话不多说先上代码

src/App.js,将项目顶层组件封装在 Provider 组件内,并将 store 对象做为其属性。这样一来,所有的子组件都可以拿到 store 中的数据

import { Provider } from 'react-redux';
import store from './store';

class App extends React.Component {

  render() {
    return (
      <Provider store={ store }>
        <Counter />
      </Provider>
    );
  }

}

export default App;

components/counter.js,有如下几点的改变

  1. 输入:原先通过 store.getState() 拿到数据,现在变成了通过 mapStateToProps,将 store 中的数据挂载到组件的 props 上
  2. 输出:原先通过 store.dispatch() 触发 action,现在变成了通过 mapDispatchToProps,将 actionsCreator 中的方法挂载到组件的 props 上。且这些 actionCreator 经过 bindActionCreators 封装之后具备了 dispatch 的功能。这样一来,在组件中可以直接调用 this.props.action() 来触发一个 action
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import actionCreator from '../actions/counter'

class Counter extends React.Component {
  render() {
    const { num, actions } = this.props;
    return (
      <div className="App">
        {
          num
        }
        <div></div>
        <button onClick={ actions.increment }>+</button>
        <button onClick={ actions.decrement }>-</button>
      </div>
    );
  }

}

const mapStateToProps = (state, ownProps) => {
  return {
    num: state.counter.num
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    actions: bindActionCreators(actionCreator, dispatch)
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Counter);

整个过程用到了几个重要的 API

Provider:顶层组件,作用是把 store 挂载到 context 上,以便下层组件可以从 context 或者 props 中获取 store

connect:高阶组件,获取到 context 上的 store 以及 actionCreator,然后封装业务组件,以属性的方式传递给业务组件

mapStateToProps:selector 选择器,从 store 中的选出组件需要的值,做为 selector 的返回值

mapDispatchToProps:selector选择器,提取某些 actionCreator,做为 selector 的返回值

下面分别大致说一下每个方法的实现过程

Provider 组件

Provider 组件的作用就是把 store 挂载到 context 上面,把项目的根组件包裹起来,这样任意一个业务组件都可以通过 context 拿到 store 中的数据

class Provider extends React.Component {
    getChildContext () {
        return {
            store: this.props.store
        }
    }
    render () {
        return Children.only(this.props.children)
    }
}

Provider.propTypes = {
    store: PropTypes.shape({
      subscribe: PropTypes.func.isRequired,
      dispatch: PropTypes.func.isRequired,
      getState: PropTypes.func.isRequired
    }),
    context: PropTypes.object,
    children: PropTypes.any
}

connect 函数

connect 是一个高阶组件,它接收 mapStateToProps、mapDispatchToProps、mergeProps、options 作为参数。它的作用就是将  store 中的 state 和 dispatch 映射到组件的 props 上。这样组件可以轻易的获取 state 和 发出 action.

render() {
  const selector = this.selector
  selector.shouldComponentUpdate = false

  if (selector.error) {
    throw selector.error
  } else {
    return createElement(WrappedComponent, this.addExtraProps(selector.props))
  }
}

mapStateToProps

store 中的 state 是整个项目的数据,而单个业务组件只需要这颗 state 树中的某几个数据。所以该对象的作用就是摘取组件所需要的几个 state。

可以看到如果我们没有传 mapStateToProps 这个参数给 connect 函数的话,connect 组件并不会监听 state 的变化来更新组件。

// if mapStateToProps is falsy, the Connect component doesn't subscribe to store state changes
shouldHandleStateChanges: Boolean(mapStateToProps),

相反,如果传了就会初始化一些监听

if (!shouldHandleStateChanges) return

  const parentSub = (this.propsMode ? this.props : this.context)[subscriptionKey]
  this.subscription = new Subscription(this.store, parentSub, this.onStateChange.bind(this))

  this.notifyNestedSubs = this.subscription.notifyNestedSubs.bind(this.subscription)
}

mapDispatchToProps

改对象的传值有三种情况:

  • function:
  • Object:这时会调用 redux 的 bindActionCreators,将这个 actionCreator 对象封装起来,是这个 creator 被调用的时候,直接就能 dispatch
  • 不传
export function whenMapDispatchToPropsIsFunction(mapDispatchToProps) {
  return (typeof mapDispatchToProps === 'function')
    ? wrapMapToPropsFunc(mapDispatchToProps, 'mapDispatchToProps')
    : undefined
}

export function whenMapDispatchToPropsIsMissing(mapDispatchToProps) {
  return (!mapDispatchToProps)
    ? wrapMapToPropsConstant(dispatch => ({ dispatch }))
    : undefined
}

export function whenMapDispatchToPropsIsObject(mapDispatchToProps) {
  return (mapDispatchToProps && typeof mapDispatchToProps === 'object')
    ? wrapMapToPropsConstant(dispatch => bindActionCreators(mapDispatchToProps, dispatch))
    : undefined
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。在编写C程序时,需要注意变量的声明和定义、指针的使用、内存的分配与释放等问题。C语言中常用的数据结构包括: 1. 数组:一种存储同类型数据的结构,可以进行索引访问和修改。 2. 链表:一种存储不同类型数据的结构,每个节点包含数据和指向下一个节点的指针。 3. 栈:一种后进先出(LIFO)的数据结构,可以通过压入(push)和弹出(pop)操作进行数据的存储和取出。 4. 队列:一种先进先出(FIFO)的数据结构,可以通过入队(enqueue)和出队(dequeue)操作进行数据的存储和取出。 5. 树:一种存储具有父子关系的数据结构,可以通过中序遍历、前序遍历和后序遍历等方式进行数据的访问和修改。 6. 图:一种存储具有节点和边关系的数据结构,可以通过广度优先搜索、深度优先搜索等方式进行数据的访问和修改。 这些数据结构在C语言中都有相应的实现方式,可以应用于各种不同的场景。C语言中的各种数据结构都有其优缺点,下面列举一些常见的数据结构的优缺点: 数组: 优点:访问和修改元素的速度非常快,适用于需要频繁读取和修改数据的场合。 缺点:数组的长度是固定的,不适合存储大小不固定的动态数据,另外数组在内存中是连续分配的,当数组较大时可能会导致内存碎片化。 链表: 优点:可以方便地插入和删除元素,适用于需要频繁插入和删除数据的场合。 缺点:访问和修改元素的速度相对较慢,因为需要遍历链表找到指定的节点。 栈: 优点:后进先出(LIFO)的特性使得栈在处理递归和括号匹配等问题时非常方便。 缺点:栈的空间有限,当数据量较大时可能会导致栈溢出。 队列: 优点:先进先出(FIFO)的特性使得

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值