React Redux 介绍

Redux 介绍

一.简介

Redux 是JavaScript的状态管理器.由Facebook的Flux演变而来,

Redux是一个可预测的状态管理容器,实质上也是Flux里面的单向数据流的思想.

Redux是第三方的JavaScript库,在需要状态管理的地方,都可以使用,通常我们都是搭配React进行使用,Redux的存在仅仅是为了状态管理.

二.Redux 三大原则

1.单一数据源

整个应用的 state被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中

可以将Store理解为全局的一个变量,并且全局只有一个Store,开发过程中,可以将state保存在内存中,从而加快开发速度

2.state是只读的

唯一改变state的方法就是触发action,action是一个用于描述已发生事件的普通对象.

action就是一个普通的对象,改变state,只能通过触发action才能完成.这样确保View和网络请求都无法直接修改状态,只是为了表达一个动作,一个修改state的意图.Store中有个dispatch,dispatch接收Action参数,然后通过Store.dispatch()触发,来改变Store中的state.

Store.dispatch({
    type:"EDIT_STATE",//Action的一个类型名称
    payload   //表示Action携带的状态,也就是数据,需要发生的行为
});

3.使用纯函数来执行修改

为了描述action如何改变state tree,你需要编写reducers

3.1 纯函数

纯函数:一个函数的返回结果只能依赖于它的参数,相同的输入,永远都会得到相同的输出,而且没有任何副作用

纯函数是函数式变成的概念,必须遵守以下约束:

  • 不能改写参数
  • 不能调用系统的API
  • 不能调用Date.now或者Math.random()等不纯的方法.因为每次得到的结果会不一样

所以,我们改变state,需要写reducers,而reducers是纯函数,就可以保证同样的State,必定得到相同的View,所以Reducer函数里面不能改变state,我们必须返回一个全新的对象.所以,如果State是对象的话,必须进行深复制操作!

三.Redux的组成

Redux由三部分组成:Action,Reducer,Store

  • Action用来表达动作或者信号

  • Reducer根据Action更新State

  • Store是存放所有的状态容器

1.Action

在Redux中,Action的概念,使用方法和创建方法与Flux基本一致,是一个用于描述发生了什么事情的JavaScript对象.也是信息的载体,Action是一个能够把state从应用传到Store的载体.

// 提供一个action信息
let action= {
    type: "TODO_ADD", //Action名称
    payload    //Action的数据行为
}

PS:Action是Store中唯一的来源

state的变化,会导致view的变化,所以,State的变化必须是View导致的.Action就是View发出的通知,表示State应该要发生变化了.

Action是一个对象,type属性是必须的,并且还是一个字符串常量.表示Action要执行的动作名称,其他属性可以自由设置

1.1 actionType

在大型项目中,我们一般使用模块或文件单独存放actionType:

//actionType.js

//创建actionTypes字典
export const TODO_ADD="TODO_ADD";
export const TODO_UPDATE="TODO_UPDATE";
export const TODO_DELETE="TODO_DELETE";
export const TODO_CLEAR="TODO_CLEAR";

//菜单字典
export const MENU_QUERY="MENU_QUERY";

使用时,在Action或Reducers中引入即可

import { TODO_ADD,TODO_UPDATE,MENU_QUERY } from '../actionTypes';

实际开发中,一个模块的功能肯定不止一个Action,难道我们每次都要定义一个Action的动作变量吗?显然不是的,我们需要生成Action的实例的动作文件

1.2 action Create
// 添加
export function addTodo(payload) {
    return {
        type: TODO_ADD,
        payload
    }
}

//修改
export function updateTodo(payload) {
    return {
        type: TODO_Edit,
        payload
    }
}

在 Redux 中的 action 创建函数只是简单的返回一个 action,这就是Action的创建

2.Reducer

Action定义了要执行的动作,但是没有说如何更改state,所以Reducer的职责就是定义整个应用的state如何更改.

Reducer的作用就是根据Action执行去更新Store中的状态

在Redux中,所有的状态都被保存在一个单一的object tree中,与Flux并不一样,Flux可以有多个Store来存储各种不同的状态.

前面说了,Reducer是一个纯函数,它接受之前的state和Action对象,并返回新的state,并且纯函数不会有副作用,只要传入的参数确定,返回的结果总数唯一的.

// 初始化state,也就是state的初始状态
let initState = {
    msg: "hello world",
    list: [{
        id: 1, task: "吃饭"
    }, {
        id: 2, task: "睡觉"
    }]
}

// 1.state不能直接修改,也就是任何时候,state都没有被改变
// 2.state的改变不是原来的state,而是我们深拷贝了一个新的state,去替换旧的
// 3.reducer 这个函数里抛出去的是深拷贝的state
export default function reducer(state = initState, action) {
    let newState = JSON.parse(JSON.stringify(state));
    switch (action.type) {
        case TODO_ADD:
            newState.list.push(action.payload);
            break;
        case TODO_DELETE:
            newState.list.filter((ele) => {
                return ele.id != action.payload;
            });
        default:
            break;
    }

    return newState;
}

PS:

  • 1.state不能直接修改,也就是任何时候,state都没有被改变

  • state的改变不是原来的state,而是我们深拷贝了一个新的state,去替换旧的

  • 3.reducer 这个函数里抛出去的是深拷贝的state

    深浅拷贝详解,以及使用方式

2.1 combineReducers()

一个应用显然不会只有那么一个Reducers,所以我们需要将Reducers进行拆解并且合并.也就是说,可以把Reducer拆解成多个单独的函数.而这单独的函数负责自己独立的state.更有利于管理好自己的代码,然后将这所有单独的函数进行合并.

combineReducers(Object)只接收一个对象参数

//引入合并Reducers的函数方法
import { createStore,combineReducers} from 'redux';

//Reducers单元模块
import todoReducers from './reducers/todo';
import menuReducers from './reducers/menu';

//合并 Reducers
const reducers = combineReducers({
    //key value形式,后面Store取值时,取key即可
    todo: todoReducers,
    menu: menuReducers
})
export default createStore (reducers);

3.Store

Redux中的Store概念和Flux中的Store基本相同,但是Redux中全局只有一个Store,用于存储整个应用的状态

强调:Redux应用只有一个单一的Store,当需要拆分数据处理逻辑时,使用Reducer组合方式,不是创建多个Store

Store的职责:

  • 维持应用的state
  • getState()获取state
  • dispatch(action) 执行一个Action,来更新state
  • subscribe(listener) 用于注册回调,监听state的变化
  • subscribe(listener) 返回的函数可以注销监听器
3.1 createStore()

Store 是通过Redux提供的createStore来创建的

//引入创建Store的函数和合并Reducers的函数方法
import { createStore, combineReducers } from 'redux';

//Reducers单元模块
import todoReducers from './reducers/todo';
import menuReducers from './reducers/menu';

//合并 Reducers
const reducers = combineReducers({
    todo: todoReducers,
    menu: menuReducers
})
//创建Store
const Store = createStore(reducers);
//抛出
export default Store;

createStore接收一个功能是reducer的函数作为参数

  • reducer(Function) 函数,可以自定义命名,不过我们一般命名为Reducer 接收2个参数,一个是当前的State和要执行的Action.返回新生成的Store对象.

createStore还有另外几个参数,有着各自的功能,我这里只介绍第一个参数.后面还有接收一个中间件的参数.

四.React中Redux的使用

Redux是不依赖于React存在的,它本身能支持React,Angular 和jQuery等.要让Redux在React上使用,需要二者建立连接,于是就有了react-redux

react-redux是基于容器组件和展示组件相互分离的开发思想

1.react-redux

安装 react-redux

npm install react-redux -S

react-redux提供了2个重要的对象 Providerconnect

2.Provider

使用react-redux时,先要在最顶层创建一个Provider的组件,用于将所有的React组件包裹起来,从而使React的所有组件都成为Provider的子组件.然后将创建好的Store,作为Provider的属性传递下去

import { Provider } from 'react-redux';
import store from '@/store'

// console.log(store);
export default class App extends React.Component {
  render() {
    return (
      <HashRouter>
        <div className="app" >
          <Provider store={store}>
            <LoyoutCom></LoyoutCom>
          </Provider>
        </div>
      </HashRouter>
    );
  }
}

3.connect

connect的主要作用是连接React组件与React Store.当前组件可以通过props获取应用中的state和Action

connect接收4个参数:

  • mapStateToProps()
  • mapDispatchToProps()
  • mergeProps()
  • options

我们项目经常使用的是前两种:mapStateToProps()mapDispatchToProps()

3.1 mapStateToProps

主要作用是将Store中的数据作为props,绑定到当前组件

//将state中的数据变成当前组件的props
function mapStateToProps(state) {
    return {
        //从Store中获取需要的state
        menuList: state.menu.menuList
    }
}  

//取值时可以直接 this.props.menuList
3.2 mapDispatchToProps

主要作用是将当前的Action作为Props绑定到当前组件

//将Action动作转为当前组件的props
function mapDispatchToProps(dispatch) {
    return {
        //派发一个Action,需要执行
        getMenuList: (params) => dispatch(queryMenu(params))
    }
}
3.3 connect高阶组件使用

connect属于高阶组件,它允许向一个现有组件添加新功能,同时不改变其结构

export default connect(mapStateToProps, mapActionToProps)(LoyoutCom);

五.middleware中间件

上面所讲的Action是发起同步的.但是如果我们每次调用接口,就需要发起异步的Action,这里就需要我们的中间件middleware了.

redux默认只支持同步的action,要想支持异步的action的行为,需要使用第三方中间件,一般使用redux-thunk

中间件的作用是把异步行为(比如调接口)的action转为3个同步的action,以此来解决redux只支持同步action的特点

1.三个同步Action:

  • 第一个 action的作用是告诉reducer有一个异步行为触发
  • 第二个 action的作用是告诉reducer异步行为执行成了,可以更细state了
  • 第三个 action的作用是告诉reducer异步行为失败了

2.使用中间件

安装redux-thunk

npm install redux-thunk -S

应用中间件

//引入创建Store的函数和合并Reducers的函数方法
import { createStore, combineReducers, applyMiddleware } from 'redux';
//Reducers单元模块
import todoReducers from './reducers/todo';
import menuReducers from './reducers/menu';

//引入中间件,作用是把异步行为(比如调接口)的action转为3个同步的action
import thunk from 'redux-thunk';

//合并 Reducers
const reducers = combineReducers({
    todo: todoReducers,
    menu: menuReducers
})
export default createStore(reducers, applyMiddleware(thunk));


applyMiddleware是createStore的第二个参数,告诉createStore如何处理中间件

3.异步的action

创建异步的action与同步的不太一样,需要dispatch 2个异步的action

import { MENU_QUERY } from '../actionTypes';
import { menuapi } from '@/utils'

//异步获取菜单的Action
export function queryMenu(params) {

    return function (dispatch) {
        menuapi.getMenuList(params).then(res => {
            //查询成功的Action
            dispatch({
                type: MENU_QUERY,
                payload: res.list
            });
        }).catch((err) => {
            //失败的Action
            dispatch({
                type: MENU_QUERY,
                payload: ''
            });
        });
    };
}

一个成功的action,一个失败的action

发起action异步行为也稍微有点出入:

//将Action动作转为当前组件的props
function mapDispatchToProps(dispatch) {
    return {
        getMenuList: (params) => dispatch(queryMenu(params))
    }
}

然后要执行当前的接口的话,需要在某个特定的时候触发,比如componentDidMount,或者事件.

六.总结Redux的工作流程

插上一张阮一峰大神写的相关Redux的工作流程图

解读步骤如下:

  • 1.View层,也就是组件中,会提交一个action
  • 2.这个action对应着 action creatores 也就是动作产生器,这个等工作产生器是一个函数,返回的是一个个action对象,而这个对象中有个type,对应着处理什么类型的动作.也就是动作携带的参数或者说载体
  • 3.然后这个action会被Store中的dispatch方法触发,派发一个action到我们的reducers里面来,这个reducers是一个纯函数,接收2个参数,分别是上一个state,和传过来的Action(动作).然后进行处理,通过type属性处理各自相应的action,但是这里不会去改变原有的state,而是在原有的state基础上进行一个深复制,然后返回一个新的newState.这正对应着Redux三大原则中的state是只读的原则.
  • 4.Store接收到来自Reducers返回的新的State
  • 5.Store根据新的State去渲染页面

猜你喜欢

转载自blog.csdn.net/liuqiao0327/article/details/107453361
今日推荐