资讯专栏INFORMATION COLUMN

【React进阶系列】手写实现react-redux api

刘玉平 / 1954人阅读

简介:简单实现react-redux基础api

react-redux api回顾


把store放在context里,所有子组件可以直接拿到store数据

使组件层级中的 connect() 方法都能够获得 Redux store
根组件应该嵌套在 
ReactDOM.render(
  
    
  ,
  rootEl
)

ReactDOM.render(
  
    
      
        
        
      
    
  ,
  document.getElementById("root")
)

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
链接组件和数据,把redux中的数据放到组件的属性中

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

如果定义该参数,组件将会监听 Redux store 的变化。任何时候,只要 Redux store 发生改变,mapStateToProps 函数就会被调用。该回调函数必须返回一个纯对象,这个对象会与组件的 props 合并

如果你省略了这个参数,你的组件将不会监听 Redux store
ownProps,则该参数的值为传递到组件的 props,而且只要组件接收到新的 props,mapStateToProps 也会被调用,被重新计算
mapStateToProps 函数的第一个参数是整个Redux store的state,它返回一个要作为 props 传递的对象。它通常被称作 selector (选择器)。 可以使用reselect去有效地组合选择器和计算衍生数据.
注意:如果定义一个包含强制性参数函数(这个函数的长度为 1)时,ownProps 不会传到 mapStateToProps

const mapStateToProps = (state, ownProps) => {
  return {
    active: ownProps.filter === state.visibilityFilter
  }
}

[mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function)

Object: 它的每个键名也是对应 UI 组件的同名参数,键值应该是一个函数(action creator),会被当作 Action creator ,返回的 Action 会由 Redux 自动发出,

Function: 会得到dispatch和ownProps(容器组件的props对象)两个参数(此时可能用到Redux 的辅助函数 bindActionCreators())

省略这个 mapDispatchToProps 参数,默认情况下,dispatch 会注入到你的组件 props 中,你可以this.props.dispatch调用
指定了该回调函数中第二个参数 ownProps,该参数的值为传递到组件的 props,而且只要组件接收到新 props,mapDispatchToProps 也会被调用

eg:

connect(mapStateToProps, {
  hideAdPanel,
  pushAdData,
})(AdPanel)

function mapDispatchToProps(dispatch) {
  return {
    todoActions: bindActionCreators(todoActionCreators, dispatch),
    counterActions: bindActionCreators(counterActionCreators, dispatch)
  }
}
知识点补充 - React高阶组件(Higher-Order Components)

高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件
高阶组件就是一个没有副作用的纯函数

使用场景:两个组件大部分代码都是重复的+且更好的封闭性,不需要关注数据的获取

import React, {Component} from "react"

class Welcome extends Component {
    constructor(props) {
        super(props);
        this.state = {
            username: ""
        }
    }

    componentWillMount() {
        let username = localStorage.getItem("username");
        this.setState({
            username: username
        })
    }

    render() {
        return (
            
welcome {this.state.username}
) } } export default Welcome; import React, {Component} from "react" class Goodbye extends Component { constructor(props) { super(props); this.state = { username: "" } } componentWillMount() { let username = localStorage.getItem("username"); this.setState({ username: username }) } render() { return (
goodbye {this.state.username}
) } } export default Goodbye;

welcome和goodbye组件相似,只能获取的数据不一样,用高阶组件,提取公共部分

import React, {Component} from "react"

export default (WrappedComponent) => {
    class NewComponent extends Component {
        constructor() {
            super();
            this.state = {
                username: ""
            }
        }

        componentWillMount() {
            let username = localStorage.getItem("username");
            this.setState({
                username: username
            })
        }

        render() {
            return 
        }
    }

    return NewComponent
}

简化welcome和goodbye

import React, {Component} from "react";
import wrapWithUsername from "wrapWithUsername";

class Welcome extends Component {

    render() {
        return (
            
welcome {this.props.username}
) } } Welcome = wrapWithUsername(Welcome); export default Welcome;

此时,理解react-redux 的connect就好理解了

ConnectedComment = connect(mapStateToProps, mapDispatchToProps)(Component);

// connect是一个返回函数的函数(就是个高阶函数)
const enhance = connect(mapStateToProps, mapDispatchToProps);
// 返回的函数就是一个高阶组件,该高阶组件返回一个与Redux store
// 关联起来的新组件
const ConnectedComment = enhance(Component);
provider实现
import React from "react"
import ReactDOM from "react-dom"
import { createStore, applyMiddleware, compose} from "redux"
import thunk from "redux-thunk"
import { counter } from "./index.redux"
// import { Provider } from "react-redux"
// 换成自己的Provider实现
import { Provider } from "./self-react-redux"
import App from "./App"

const store = createStore(counter, compose(
  applyMiddleware(thunk),
  window.devToolsExtension ? window.devToolsExtension() : f => f
))
ReactDOM.render(
  (
    
      
    
  ),
  document.getElementById("root"))

./self-react-redux

import React from "react"
import PropTypes from "prop-types"

export function connect(){
}

class Provider extends React.Component{
  static childContextTypes = {
    store: PropTypes.object
  }
  getChildContext() {
    return { store: this.store }
  }
  constructor(props, context) {
    super(props, context)
    this.store = props.store
  }
  render(){
    return this.props.children
  }
}
connect实现

demo

import React from "react"
// import { connect } from "react-redux"
import { connect } from "./self-react-redux"
import { addGun, removeGun, addGunAsync } from "./index.redux"

@connect(
    // 你要state什么属性放到props里
    state=>({num:state.counter}),
    // 你要什么方法,放到props里,自动dispatch
    { addGun, removeGun, addGunAsync }
)
class App extends React.Component{
    render(){
        return (
            

现在有机枪{this.props.num}把

) } } export default App

./self-react-redux.js


// 高阶组件的写法
export function connect(maoStateToProps, mapStateToProps) {
  return function(WrapComponent) {
    return class ConnectComponent extends React.Component{
 
    }
  }
}


import React from "react"
import PropTypes from "prop-types"
import { bindActionCreator } from "./self-redux"
// 使用简写形式
// connect负责链接组件,给到redux里的数据放在组件的属性里
// 1. 负责接收一个组件,把state里的一些数据放进去,返回一个组件
// 2. 数据变化的时候,能通知组件
export const connect = (
  mapStateToProps = state => state,
  mapDispatchToProps ={}
) => (WrapComponent) => {
  return class ConnectComponent extends React.Component {
    static contextTypes = {
      store: PropTypes.object
    }
    constructor(props, context){
      super(props, context)
      this.state = {
        props: {}
      }
    } 
    // 2 实现了mapStateToProps
    componentDidMount() {
      const { store } = this.context
      store.subscribe(() => this.update())
      this.update()
    }
    update() {
      const { store } = this.context
      // store.getState()这就是为什么mapStateToProps函数里面能拿到state 
      const stateProps = mapStateToProps(store.getState())
      // 方法不能直接给,因为需要dispatch
        /**
          function addGun() {
            return { type: ADD_GUN }
          }
          直接执行addGun() 毫无意义
          要 addGun = () => store.dispatch(addGun()) 才有意义,其实就是把actionCreator包了一层
          bindActionCreators在手写redux api实现了
         */
      const dispatchProps = bindActionCreators(mapDispatchToProps, store.dispatch)
      // 注意state的顺序问题会覆盖
      this.setState({
        props: {
          ...this.state.props,
          ...stateProps,
          ...dispatchProps,
        }
      })
    }
    // 1
    render() {
      return 
    }
  }
}

./self-redux.js

// creators: {addGun, removeGun, addGunAsync}
// creators[v]:addGun(参数)
// 返回:(参数) => dispatch(addGun(参数))
 function bindActionCreator(creator, dispatch) {
   return (...args) => dispatch(creator(...args))
 }

 export function bindActionCreators(creators, dispatch) {
   let bound = {}
   Object.keys(creators).forEach( v => {
     let creator = creators[v]
     bound[v] = bindActionCreator(creator, dispatch)
   })
   return bound
 }
// 简写
 export function bindActionCreators(creators, dispatch) {
  return Object.keys(creators).reduce((ret, item) => {
     ret[item] =  bindActionCreator(creators[item], dispatch)
     return ret
   }, {})
 }

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/98563.html

相关文章

  • React进阶系列手写redux api

    摘要:每个接受的和函数作为命名参数,并返回一个函数。调用链中最后一个会接受真实的的方法作为参数,并借此结束调用链。 简介: 手写实现redux基础api createStore( )和store相关方法 api回顾: createStore(reducer, [preloadedState], enhancer) 创建一个 Redux store 来以存放应用中所有的 state reduc...

    Elle 评论0 收藏0
  • React-redux进阶之Immutable.js

    摘要:的优势保证不可变每次通过操作的对象都会返回一个新的对象丰富的性能好通过字典树对数据结构的共享的问题与原生交互不友好通过生成的对象在操作上与原生不同,如访问属性,。 Immutable.js Immutable的优势 1. 保证不可变(每次通过Immutable.js操作的对象都会返回一个新的对象) 2. 丰富的API 3. 性能好 (通过字典树对数据结构的共享) Immutab...

    孙淑建 评论0 收藏0
  • React-Redux进阶(像VUEX一样使用Redux)

    摘要:前言是一个非常实用的状态管理库,对于大多数使用库的开发者来说,都是会接触到的。在使用享受其带来的便利的同时,我们也深受其问题的困扰。只支持同步,让状态可预测,方便测试。粗暴地级联式刷新视图使用优化。 前言 Redux是一个非常实用的状态管理库,对于大多数使用React库的开发者来说,Redux都是会接触到的。在使用Redux享受其带来的便利的同时, 我们也深受其问题的困扰。 redux...

    levius 评论0 收藏0
  • React+ Redux + React-route + Axios 实战,很适合进阶

    摘要:前言前段时间学习完了的基础自己网上找了一些实战项目做了几个感觉项目不是很全面就想做一个完整的项目来提升自己的水平以前学习的时候就看过大神的项目所以自己打算用重写它后端数据还是用实在没有精力撸后端感谢大神该项目是饿了么目前开发了登录注册购 前言 前段时间学习完了React的基础,自己网上找了一些实战项目,做了几个感觉项目不是很全面,就想做一个完整的项目来提升自己的React水平.以前学习...

    phpmatt 评论0 收藏0
  • React 新 Context API 在前端状态管理的实践

    摘要:本文转载至今日头条技术博客众所周知,的单向数据流模式导致状态只能一级一级的由父组件传递到子组件,在大中型应用中较为繁琐不好管理,通常我们需要使用来帮助我们进行管理,然而随着的发布,新成为了新的选择。 本文转载至:今日头条技术博客showImg(https://segmentfault.com/img/bVbiNJO?w=900&h=383);众所周知,React的单向数据流模式导致状态...

    wing324 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<