React ( redux 的使用流程及简单的案例 ,redux的数据划分使用,以及react-redux,react-thunk的使用)

redux

  1. redux基础
  2. redux中数据的划分( reducer 划分)
  3. redux中的中间件

组成部分

  1. store 数据的管理者
  2. view react的组件来充当
  3. actionsCreators 动作的创建者, 用来发送一个 action ❥(^_-)
  4. reducer 动作的触发者, 用来修改数据的 ,reducer是一个纯函数,它里面有一个返回值, 返回值是什么, 那么newState就是什么

redux的基础使用流程

React ( redux 的使用流程及简单的案例 ,redux的数据划分使用,以及react-redux,react-thunk的使用)_第1张图片
得有一个工具 redux

  1. 安装 redux
    $ yarn add redux
  2. 创建一个共享的数据存储仓库 文件夹 store
    src
    store
    index.js
  3. store的创建
    import { createStore } from 'redux'

    const store = createStore(reducer)

    export default store
 
    //  redux 中store身上的方法
    //     dispatch: ƒ dispatch(action)
    //     getState: ƒ getState()
    //     replaceReducer: ƒ replaceReducer(nextReducer)
     //     subscribe: ƒ subscribe(listener)
    //     Symbol(observable): ƒ observable()
     
  1. 创建reducer.js 纯函数

     /* 
     reducer 是一个纯函数 ,函数接收两个参数,第一个参数是 previousState, 第二个参数是 action
    
     previousState = state 赋初始值时,会将地址浅拷贝给previousState,当previousState改变时,
     会影响state, 我们应该避免这种情况,所以我们要做一个深拷贝,我们使用最简单的形式就是:解构赋值
    
     那么我们就可以直接去管newState
     */
    
        import state from './state'
        import * as type from './type'
        const reducer = ( previousState = state, action ) => {


        var newState = {
            ...previousState
        }

        switch ( action.type ) {
            case type.ADD_TODOS:
                //修改数据的
                newState.todos.push({
                id: newState.todos.length + 1,
                text: action.payload
                })
            break;
        
            default:
            break;
        }

        console.log( newState )

        return  newState
        }


        // module.exports = reducer

        export default reducer
  1. 初始化状态
    创建 state.js
        const state = {
            todos: [
                {},{}
            ]
        }
    import state from './state'

    const reducer = (previousState = state,action) => {
        let new_state = previousState
        return new_state
    }
  1. reducer要将数据 给 store
    import reducer from './reducer'

    const store = createStore(reducer)
  1. store —> view

    view
    import store from ‘./store’

     store.getState() 就可以拿到数据了
    
     写无状态组件
    
     写列表渲染函数
     key要加
    
  2. view 用户操作 — 》 actionCreators

创建 actionCreators.js

    import store from './index'
    let actionCreators = {
        //方法
        fn(){
            // 1. 创建 action 
            let action = {
                type: 常量,
                payload
            }
            // 2. 发送 action
            store.dispatch(action)
        }
    }
    export default actionCreators
  1. reducer 接收 actionCreator 发来的 action
    const reducer = (previousState = state ,action) => {
        let new_state = previousState
        switch (action.type) {
            case type.xxx:
                // 数据的修改
            break;
        
            default:
            break;
        }
        return new_state
    }
  1. 视图的更新 —》 重新获取数据
    componentWillMount(){
        store.subscribe(()=>{
            this.setState({
                todos: store.getState().todos
            })
        })
    }

redux进阶使用流程

reducer划分

分析
    一个项目: 
        banenr
        home
        mine
        login
        register
        detail
        shopcar
        会员
        普通用户数据

解决: 希望的一个类型数据一个模块 ---- 》 reducer划分 combineReducers


分析: 我们希望我们的store下面每一个文件夹就是一个 类型 的数据包
解决: 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

####reducer划分
分析
一个项目:
banenr
home
mine
login
register
detail
shopcar
会员
普通用户数据

解决: 希望的一个类型数据一个模块 ---- 》 reducer划分 combineReducers


分析: 我们希望我们的store下面每一个文件夹就是一个 类型 的数据包
解决: 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

react-redux

在使用redux的过程中,我们发现有这么几个动作老是重复的:

组件想要使用store的数据,必须在constructor中利用store.getState获取到数据再挂载到自己的状态上

组件想要获取更改后的最新的数据,需要在初始化钩子函数中,利用store.subscribe注册一个监听函数,在该函数中去获取最新的状态同步到组件的状态中

而且,actionCreator的动作有点多,不只创建了action,还得负责发送action

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

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

核心概念

容器组件(智能组件)、UI组件(木偶组件)

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的方法,导致这个组件引入了很多东西,其实我们可以将这些逻辑封装取出

在react脚手架的入口文件index.js中 引入react-redux

需要先安装 yarn add redux
用Provider包裹App
React ( redux 的使用流程及简单的案例 ,redux的数据划分使用,以及react-redux,react-thunk的使用)_第2张图片

包裹之后可以看到如下内容

React ( redux 的使用流程及简单的案例 ,redux的数据划分使用,以及react-redux,react-thunk的使用)_第3张图片

在要使用的组件中引入

  import React, { Component,Fragment } from 'react';
  import { connect } from 'react-redux'
  import { bindActionCreators } from 'redux'
  import actionCreators from '../../store/list/actionCreators'

组件导出的部分

    export default connect( mapStateToProps,mapDispatchToProps )(List)
    

绑定后就可以在React辅助工具中看到如下内容

React ( redux 的使用流程及简单的案例 ,redux的数据划分使用,以及react-redux,react-thunk的使用)_第4张图片

组件内的使用方法

所有的方法和状态都在props上
React ( redux 的使用流程及简单的案例 ,redux的数据划分使用,以及react-redux,react-thunk的使用)_第5张图片

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的时候使用中间件
    store里面index,js的内容

  	import { createStore,applyMiddleware } from 'redux'
  	
  	import thunk from 'redux-thunk' 
  	
  	import reducer from './reducer'
  	
  	const store = new createStore( reducer,applyMiddleware( thunk ) )
  	
  	export default store
import { createStore, applyMiddleware } from 'redux'

import thunk from 'redux-thunk'

import reducer from './reducer'

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

使用方法

const actionCreators = {
    getTodos () {
        return dispatch => {
            fetch('/data.json')
            .then( res => res.json() )
            .then( res =>{
                let action ={
                    type:type.GET_TODOS,
                    payload: res
                }
                dispatch( action )
            } )
            .catch( err => {
                console.log( err )
            } )
        }
    }
}
  1. 这个时候,actionCreator的方法就可以返回一个能接收到dispatch的一个函数,我们可以在这个函数中进行异步操作之后,将actionCreator创建好的action给发送

你可能感兴趣的:(React ( redux 的使用流程及简单的案例 ,redux的数据划分使用,以及react-redux,react-thunk的使用))