阅读 221

React-Redux-3 的用法

UI组件和容器组件

  • UI组件

    class One extends Component {
        render() {
            let { n,dec,inc } = this.props
            return (
                <div>
                    <button onClick={dec}>-</button>
                    {n}
                    <button onClick={inc}>+</button>
                </div>
            )
        }
    }复制代码
    • 只负责展示UI,不带业务逻辑

    • 没有状态(即不使用this.state这个变量)

    • 所有数据都由参数(this.props)提供

    • 不使用任何 Redux 的 API

    • 特点

    • 例子

  • 容器组件

    class OneContainer extends Component {
        constructor(props) {
            super(props)
            this.state = {
                n: store.getState().n
            }
            //参数是一个函数
            store.subscribe(this.change)
        }
        //当store里数据修改的时候会执行这个回调函数
        change = () => {
            this.setState({
                n: store.getState().n
            })
        }
        dec() {
            store.dispatch(actionCreator.decAction(1))
        }
        inc() {
            store.dispatch(actionCreator.incAction(2))
        }
        render(){
            return <One n={this.state.n} inc={this.inc} dec={this.dec} />
        }
    }复制代码

    以上例子来源

    • 负责管理数据和业务逻辑,不负责 UI 的呈现

    • 带有内部状态

    • 使用 Redux 的 API

    • 特点

    • 例子

  • 小结:

    • UI组件一般都可以写成无状态组件。无状态组件性能比较高,它就是一个函数。而普通子组件,会有一些生命周期函数。当一个组件只负责页面的渲染,没有任何逻辑的时候就可以将这个组件写成一个性能较高的无状态组件。

    • UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑

    • 将二者分离的原因:

connect()

  • 作用

    从 UI 组件生成容器组件,即将两类组件 (UI组件,容器组件) 连接起来

  • 问题思考:

    • 输入逻辑:外部的数据(即state对象)如何转换为 UI 组件的参数;

    • 输出逻辑:用户发出的动作如何变为 Action 对象,从 UI 组件传出去。

  • connect方法的完整API

    import { connect } from 'react-redux'
    const VisibleTodoList = connect(
      mapStateToProps,
      mapDispatchToProps
    )(TodoList)复制代码

    两个参数定义UI组件的业务逻辑,(详见后文)

    • 作用:用来建立 UI 组件的参数到store.dispatch方法的映射。后者负责输出逻辑,即将用户对 UI 组件的操作映射成 Action。即定义了哪些用户的操作应该当作 Action,传给 Store。

    • 如果mapDispatchToProps是一个函数,会得到dispatchownProps(容器组件的props对象)两个参数。

    • 作用:建立一个从(外部的)state对象到(UI 组件的)props对象的映射关系。负责输入逻辑,即将state映射到 UI 组件的参数(props

    • 何时引发UI渲染?

      // 容器组件的代码
      //    <FilterLink filter="SHOW_ALL">
      //      All
      //    </FilterLink>
      
      const mapStateToProps = (state, ownProps) => {
        return {
          active: ownProps.filter === state.visibilityFilter
        }
      }复制代码
    • connect方法可以省略mapStateToProps参数,那样的话,UI 组件就不会订阅Store,就是说 Store 的更新不会引起 UI 组件的更新。

    • mapStateToProps会订阅 Store,每当state更新的时候,就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染。

    • mapStateToProps的第一个参数总是state对象,还可以使用第二个参数,代表容器组件的props对象。

    • 使用ownProps作为参数后,如果容器组件的参数发生变化,也会引发 UI 组件重新渲染(暂时没有看懂例子)。

    • mapStateToProps

    • mapDispatchToProps

           const mapDispatchToProps = (
             dispatch,
             ownProps
           ) => {
             return {
               onClick: () => {
                 dispatch({
                   type: 'SET_VISIBILITY_FILTER',
                   filter: ownProps.filter
                 });
               }
             };
           }复制代码

      从上面代码可以看到,mapDispatchToProps作为函数,应该返回一个对象,该对象的每个键值对都是一个映射,定义了 UI 组件的参数怎样发出 Action。

connect 将当前组件和 state,action 联系起来,使得可以在组件中调用action中的方法和state中的数据 该段来源

  • @connect Decorator - 装饰器(文章来源)

    //定义一个函数,也就是定义一个Decorator,target参数就是传进来的Class。
    //这里是为类添加了一个静态属性
    function testable(target) {
      target.isTestable = true;
    }
    
    //在Decorator后面跟着Class,Decorator是函数的话,怎么不是testable(MyTestableClass)这样写呢?
    //我只能这样理解:因为语法就这样,只要Decorator后面是Class,默认就已经把Class当成参数隐形传进Decorator了。
    @testable
    class MyTestableClass {}
    
    console.log(MyTestableClass.isTestable) // true复制代码
    import { connect } from 'react-redux';
    class MyApp extends React.Component {
      // ...define your main app here
    }
    export default connect(mapStateToProps, mapDispatchToProps)(MyApp);复制代码
    import { connect } from 'react-redux';
    @connect(mapStateToProps, mapDispatchToProps)
    export default class MyApp extends React.Component {
      // ...define your main app here
    }复制代码
    • 第一步需要安装npm依赖

    • 第二步需要在package.json文件中配置一下

    • 使用装饰器需要的步骤

      npm install --save babel-plugin-transform-decorators-legacy复制代码
        "plugins": [\
        ["@babel/plugin-proposal-decorators", { "legacy": true }],\
        ]复制代码
    • 不用装饰器和使用装饰器的区别

    • 装饰器(Decorator)是一个函数,用来修改类的行为。

    1. 使用装饰器

    1. 不用装饰器

< Provider > 组件

  • connect方法存在的不足:使用该方法生成容器组件以后,需要让容器组件拿到state对象,才能生成 UI 组件的参数。

    import { Provider } from 'react-redux'
    import { createStore } from 'redux'
    import todoApp from './reducers'
    import App from './components/App'
    
    let store = createStore(todoApp);
    
    render(
      <Provider store={store}>
        <App />
      </Provider>,
      document.getElementById('root')
    )复制代码

    上面代码中,Provider在根组件外面包了一层,这样一来,App的所有子组件就默认都可以拿到state了。

    • 低效的解决方案:将state对象作为参数,传入容器组件,一级一级将state传下去以备组件使用。

    • 高效的解决方案:React-Redux 提供Provider组件,可以让容器组件拿到state

React- Router 路由库

使用React-Router的项目,与其他项目没有不同之处,也是使用ProviderRouter外面包一层,毕竟Provider的唯一功能就是传入store对象。

const Root = ({ store }) => (
  <Provider store={store}>
    <Router>
    <Route path="/" component={App} />
    </Router>
  </Provider>
);


作者:Simon、
链接:https://juejin.cn/post/7032487201573175304


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐