zoukankan      html  css  js  c++  java
  • react深入

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

    react-redux api回顾

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

    
    使组件层级中的 connect() 方法都能够获得 Redux store
    根组件应该嵌套在 &lt;Provider&gt; 中
    
    
    
    ReactDOM.render(
      &lt;Provider store={store}&gt;
        &lt;MyRootComponent /&gt;
      &lt;/Provider&gt;,
      rootEl
    )
    
    ReactDOM.render(
      &lt;Provider store={store}&gt;
        &lt;Router history={history}&gt;
          &lt;Route path="/" component={App}&gt;
            &lt;Route path="foo" component={Foo}/&gt;
            &lt;Route path="bar" component={Bar}/&gt;
          &lt;/Route&gt;
        &lt;/Router&gt;
      &lt;/Provider&gt;,
      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) =&gt; {
      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 (
                &lt;div&gt;welcome {this.state.username}&lt;/div&gt;
            )
        }
    }
    
    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 (
                &lt;div&gt;goodbye {this.state.username}&lt;/div&gt;
            )
        }
    }
    
    export default Goodbye;
    

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

    
    import React, {Component} from 'react'
    
    export default (WrappedComponent) =&gt; {
        class NewComponent extends Component {
            constructor() {
                super();
                this.state = {
                    username: ''
                }
            }
    
            componentWillMount() {
                let username = localStorage.getItem('username');
                this.setState({
                    username: username
                })
            }
    
            render() {
                return &lt;WrappedComponent username={this.state.username}/&gt;
            }
        }
    
        return NewComponent
    }
    
    简化welcome和goodbye
    
    import React, {Component} from 'react';
    import wrapWithUsername from 'wrapWithUsername';
    
    class Welcome extends Component {
    
        render() {
            return (
                &lt;div&gt;welcome {this.props.username}&lt;/div&gt;
            )
        }
    }
    
    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 =&gt; f
    ))
    ReactDOM.render(
      (
        &lt;Provider store={store}&gt;
          &lt;App /&gt;
        &lt;/Provider&gt;
      ),
      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=&gt;({num:state.counter}),
        // 你要什么方法,放到props里,自动dispatch
        { addGun, removeGun, addGunAsync }
    )
    class App extends React.Component{
        render(){
            return (
                &lt;div&gt;
                    &lt;h1&gt;现在有机枪{this.props.num}把&lt;/h1&gt;
                    &lt;button onClick={this.props.addGun}&gt;申请武器&lt;/button&gt;                
                    &lt;button onClick={this.props.removeGun}&gt;上交武器&lt;/button&gt;                
                    &lt;button onClick={this.props.addGunAsync}&gt;拖两天再给&lt;/button&gt;                
                &lt;/div&gt;
            )
        }
    }
    
    
    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 =&gt; state,
      mapDispatchToProps ={}
    ) =&gt; (WrapComponent) =&gt; {
      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(() =&gt; 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 = () =&gt; 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 &lt;WrapComponent {...this.state.props}&gt;&lt;/WrapComponent&gt;
        }
      }
    }
    

    ./self-redux.js

    
    // creators: {addGun, removeGun, addGunAsync}
    // creators[v]:addGun(参数)
    // 返回:(参数) =&gt; dispatch(addGun(参数))
     function bindActionCreator(creator, dispatch) {
       return (...args) =&gt; dispatch(creator(...args))
     }
    
     export function bindActionCreators(creators, dispatch) {
       let bound = {}
       Object.keys(creators).forEach( v =&gt; {
         let creator = creators[v]
         bound[v] = bindActionCreator(creator, dispatch)
       })
       return bound
     }
    // 简写
     export function bindActionCreators(creators, dispatch) {
      return Object.keys(creators).reduce((ret, item) =&gt; {
         ret[item] =  bindActionCreator(creators[item], dispatch)
         return ret
       }, {})
     }
    

    原文地址:https://segmentfault.com/a/1190000016759675

  • 相关阅读:
    zoj 3195 Design the city LCA Tarjan
    hdu 2586 How far away ? 离线LCA
    洛谷 P3379 【模板】最近公共祖先(LCA)Tarjan离线
    codeforces #446 892A Greed 892B Wrath 892C Pride 891B Gluttony
    设计模式(16)---原型模式
    设计模式(15)---享元模式
    设计模式(14)---组合模式
    设计模式(13)---外观模式
    设计模式(12)---适配器模式
    设计模式(11)---代理模式
  • 原文地址:https://www.cnblogs.com/lalalagq/p/9903724.html
Copyright © 2011-2022 走看看