redux和react-redux、redux-thunk

redux

redux也是一个架构思维, 在这个架构思维中 React 充当是 视图 V

------------- redux 基础 – start ----------------------------------

redux使用流程 ( todolist – 增加一条数据 )

  1. redux是一个架构思维,我们实现需要一个工具,这个工具叫做redux
  2. 安装redux
    $ yarn add redux
  3. 在src下新建一个store,store中新建index.js用来打造store
  import { createStore } from 'redux'
  import reducer from './reducer'

  const store = createStore( reducer ) // 不加new   createStore() 参数不是一个 Object 而是一个Function

  export default store 

  1. 在store下新建一个state
  const state = {
    todos: [
      {
        id: 1,
        task: '任务一'
      }
    ]
  }
  export default state 
  1. 在 store下新建一个 reducer
  import state from './state'
  const reducer = ( previousState = state , action ) => {
    const newState = {
      ...previousState           // 解构的原因是为了做深拷贝,我们操作newState,不会影响state
    }
    return newState
  }

  export default reducer 
  1. 在你想要使用的组件中直接引用 store
    import React, { Component,Fragment } from 'react'

    import store from '../store'

    class Content extends Component{

      constructor () {
        super()
        this.state = {
          todos: store.getState()
        }
      }

      render () {
        return (
          <Fragment>
            <div>
              <ul>
                <li> 1 </li>
              </ul>
            </div>
          </Fragment>
        )
      }

    }

    export default Content 
  1. 进行用户交互 React component — > actionCreators

  2. 在store下新建 actionCreators.js

import * as type from './type'
import store from './index'

const actionCreators = {
  add_todos_item ( val ) {
    //动作的创建

    const action = {
      type: type.ADD_TODOS_ITEM,
      payload: val // 负载数据
    }

    // 动作的发送
    store.dispatch( action )
  }
}


export default actionCreators

  1. 在Button组件中触发 actionCreators中 的方法
    import React, { Component,Fragment } from 'react'
    import actionCreators from './../store/actionCreators';

    class Button extends Component{

      add = () => {
        let val = this.input.value
        actionCreators.add_todos_item( val )
        this.input.value = ''
      }

      render () {
        return (
          <Fragment>
            <div>
              <input type = "text" ref = { el => this.input = el } />
              <br/>
              <button onClick = { this.add }> + </button>
            </div>
          </Fragment>
        )
      }

    }

    export default Button 
  1. 在 reducer中修改数据
  import state from './state'

  // const state = require( './state' )

  import * as type from './type'

  const reducer = ( previousState = state,action) => {
    let newState = {
      ...previousState
    }

    //判断用户进行了那个用户交互 ,操作新状态

    switch ( action.type ) {
      case type.ADD_TODOS_ITEM:

        //修改新状态
        newState.todos.push({
          id: newState.todos.length + 1,
          task: action.payload
        })
        
        break;
    
      default:
        break;
    }

  
    

    return newState
  }


  export default reducer 
  1. 进行数据个更新,通过store的订阅功能进行更新,也就是组件需要重新赋值一次数据
  2. 在Content组件中进行订阅
 componentDidMount () {
   store.subscribe( () => {
     this.setState({
       todos: store.getState().todos
     })
   })
 }

------------- redux 基础 – end ----------------------------------

------------- redux 进阶 – start ----------------------------------

redux – reducer – 划分

  1. 分析
    一个项目:

    • banenr
    • home
    • mine
    • login
    • register
    • detail
    • shopcar
    • 会员
    • 普通用户数据
  2. 解决: 希望的一个类型数据一个模块 ---- 》 reducer划分 combineReducers

  3. 分析: 我们希望我们的store下面每一个文件夹就是一个 类型 的数据包

  4. 解决: redux combineReducers
    每一个数据包的目录结构

    • store
      • home
        • state.js
        • type.js
        • reducer.js
        • actionCreator.js
      我们需要一个统一的redcuer的管理者
    
          /* 
              这里的reducer才是真正的统一管理者
          */
          import {combineReducers} from 'redux'
      import todolist from './todolist/reducer'
    
          const reducer = combineReducers({
              todolist
      })
    
      export default reducer 
    

使用的时候

  store.getState().todolist.todos

redux – redux-thunk – 实现异步请求和辅助发送action

  1. 问题: 我们在更新视图时,在组件中每次都要进行 store 的订阅,代码是冗余的
  2. 问题: 我们在触发actionCreators中的方法时,触发形式的书写也很相似
  3. 问题: 后端数据交互往哪里写? actionCreators中写,actionCreators不是用来创建动作的么?

所以,我们引入了 react-redux 工具来处理这些问题

综上: 我们通过 几个工具来解决

Provider bindActionCreators

react-redux只是一个辅助工具,只是将react和redux进行更好的连接的桥梁工具

核心概念

容器组件(智能组件)、UI组件(木偶组件) 非受控组件 ref受控组件

react-redux觉得如果一个组件想要使用到store中的数据或者是actionCreator的方法,我们都应该将其变化为容器组件包裹UI组件的样子

其中,容器组件负责连接store,将状态、方法传递给UI组件,UI组件从属性上取得这些api后进行使用

而且,不需要担心是容器组件可以根据UI组件来生成

核心API

Provider 、 connect(mapStateToProps,mapDistpatchToProps)

Provider负责将store相关的api,传入到内部所有的容器组件中

connect负责根据UI组件来生成容器组件

使用方法与细节

  1. 需要安装react-redux工具

  2. 需要在组件的最外层套上Provider组件,并为其传入store

  3. 利用connect将需要使用store相关api的组件变成容器组件嵌套UI组件的模式

    connect方法的返回值是一个函数,这个函数接收到UI组件之后会返回一个容器组件,容器内部已经嵌套了UI组件

    Provider组件会利用context上下文将自己属性中store传递给自己的子级组件,而容器组件会取得context上面的store相关的api

    我们可以在connect函数中传入mapStateToProps/mapDispatchToProps参数来掌控容器组件给UI组件传递属性的过程

    mapStateToProps的作用:

    将store中的state传递到UI组件的属性上
    值为一个函数,接收到的就是store中的state
    返回值是什么,UI组件的属性上就有什么
    并且,因为容器组件中已经做好了store.subscribe的处理,所以一旦store中的状态变化,容器组件就马上能得知,就会重新给UI组件传入新的数据

     问题: 坑  ? 我们的store中的数据在更新, 但是里面的容器组件中的 props 不更新
    
     分析: 先从组件上着手,查看我们书写的代码, 发现代码没有问题的, 这个时候我们就要去查看数据来源, 而数据来源来自于  reducer , 然后输出一下数据, 发现数据渲染了三次 , 有两次是一个组件在创建的时候, 数据从无到有, 还有一次是容器组件产生的 , 后面我们发送我们的new_state一直在重复初始化, 
    
     解决方案: 
         let new_state = {...previousState}
    

    mapDispatchToProps的作用:

    可以将能使用到dispatch的一些方法传递到UI组件上
    值为一个函数,接收到的就是store中的dispatch
    返回什么,UI组件的属性上就有什么
    这个时候actionCreator就变得很纯粹,只需要创建action,dispatch action的动作可以放到mapDispatchToProps的方法中,也就说,在mapDispatchToProps给UI组件传递的函数中将actionCreator创造好的action给dispatch走

    但是这样的写法优点不舒服,因为actionCreator里有一个方法,还需要在mapDispatchToProps里再写一个方法

    所以可以利用redux中的bindActionCreators将actionCreator中的方法直接放入到UI组件中并且将其返回的action给直接dispatch走

    因为在组件中既要用到store中的状态,也要用到actionCreator的方法,导致这个组件引入了很多东西,其实我们可以将这些逻辑封装取出

    group-todolist.js:

    import actionCreator from ‘…/store/todolist/actionCreator’
    import { connect } from ‘react-redux’
    import { bindActionCreators } from ‘redux’

    let GroupTodolist = connect(state => state.todolist, dispatch => {
    return bindActionCreators(actionCreator, dispatch)
    })

    export default GroupTodolist


TodoContent:

import GroupTodolist from '../../modules/group-todolist'

....

export default GroupTodolist(TodoContent)

redux-thunk 工具

我们上面的使用方法很简单,也很舒服

但是有一点小问题,如果我们有了异步操作,比如我们会先执行一个ajax调用之后再去更改状态的话,这个异步动作,没有地方放了

  1. 我们不能把异步动作放到组件中,因为UI组件只负责使用数据,如果有其他的异步代码,让UI组件组件不纯粹

  2. 理论上来说放到actionCreator的方法中最合适,但是,因为actionCreator目前只是专注于创建action和返回action,无法放入异步操作

所以,我们需要用到redux的中间件工具:redux-thunk、redux-promise、redux-saga…

在这里我们研究一下redux-thunk

它的使用方法及其简单:

  1. 安装redux-thunk

  2. 在创建store的时候使用中间件

    import { createStore, applyMiddleware } from ‘redux’

    import thunk from ‘redux-thunk’

    import reducer from ‘./reducer’

    const store = createStore(reducer, applyMiddleware(thunk) )

  3. 这个时候,actionCreator的方法就可以返回一个能接收到dispatch的一个函数,我们可以在这个函数中进行异步操作之后,将actionCreator创建好的action给发送

------------- redux 进阶 – end ----------------------------------

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值