千丝万缕的 react redux react-redux

214 阅读3分钟

前言

redux一直是初学者比较难理解的一部分。我们经常在项目里面看到react,redux, react-redux,那么这三者之间有什么联系呢?

  • react: 实现ui的一个框架,负责组件ui的渲染。
  • redux: 数据管理中心。
  • react-redux: 连接组件和数据中心。

所以,其实react和redux没有任何关系。redux只是管理数据的,不关心ui渲染。因此,我们平常也经常看到react + mobx的组合。

数据驱动

我们远古时期用到的JQuery,改变界面必须通过获取dom来操作,无疑是很麻烦的,虽然后面出现一些动态模板,但是这样我们也是需要重新写一次动态模板,重新生成xml。而现在大家常用的无论是Vue还是React都是所谓的数据驱动的模式,通过改变data或者state来改变view。数据驱动的模式是怎么样的呢?我们用下面这张图来介绍一下:

redux

三个原则

  • 唯一数据源
  • 数据源只能通过纯函数(reducer)修改
  • 数据只读

三大核心

  • store

// store/state.js
export default {
    pageTitle: '首页', //同步数据
    infoList: [] // 异步数据(用异步接口获取)
}



// store/index.js
import { applyMiddleware, createStore } from 'redux'

// 中间件,作用:如果不使用该中间件,当我们dispatch一个action时,需要给dispatch函数传入action对象;但如果我们使用了这个中间件,那么就可以传入一个函数,这个函数接收两个参数:dispatch和getState。这个dispatch可以在将来的异步请求完成后使用,对于异步action很有用
import thunk from 'redux-thunk'
import reducers from './reducers'

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

export default store;

store是由redux的createStore(reducer, defaultState)生成的,有三个方法:

getState():用于获取store
dispatch(action): 分发action,唯一改变数据源的方式。
subscribe(listener): 注册监听者。
  • reducer

//store/reducers.js
import { combineReducers } from 'redux'

import defaultState from './state'

// 一个reducer就是一个函数
function pageTitle(state=defaultState.pageTitle, action) {
    switch(action.type){
        case 'SET_PAGE_TITLE':
            return action.data
        default:
            return state
    }
}

function infoList(state=defaultState.infoList, action){
    switch(action.type){
        case 'SET_INFO_LIST':
            return action.data
        default:
            return state
    }
}

export default combineReducers({
    pageTitle,
    infoList
})

reducer是一个纯函数,根据prevState和action,得到新的state。

  • action

// store/actions.js
import api from '../axios/index'
export function setPageTitle(data){
    return (dispatch, getState) => {
        dispatch({
            type: 'SET_PAGE_TITLE',
            data
        })
    }
}


export function setInfoList(data){
    return (dispatch, getState) => {
        // 异步请求
        api.$http.getCourse({ status: 'open'})
            .then(res => {
                dispatch({
                    type: 'SET_INFO_LIST',
                    data: res.data
                })
            })
        
    }
}

action其实就是一个对象,主要的是包含一个type属性,表示要执行的动作。

  • store + reducer + action

react-redux

react和redux本身没有关系,是react-redux把它们联系起来。

provider

provider实现store的全局访问。 原理:使用React的context,context可以实现跨组件之间的传递。

import React from 'react';
import ReactDOM from 'react-dom';
import Router from './router/index'
import * as serviceWorker from './serviceWorker';
import { Provider } from 'react-redux'
import store from './store/index'
import './index.css';

console.log(store)

ReactDOM.render(
  <div className='App'>
    <Provider store={store}>
      { Router() }
    </Provider>
  </div>,
  document.getElementById('root')
);

connect

connect是连接react和redux。

//mapStateToProps: 将state映射到组件的props中
const mapStateToProps = state => {
  return {
    pageTitle: state.pageTitle,
    infoList: state.infoList
  };
};

// mapDispatchToProps: 将dispatch映射到组件的props中
const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    setPageTitle(data) {
	dispatch(setPageTitle(data));
    },
    setInfoList(data) {
      dispatch(setInfoList(data));
    }
  }; 
};
export default connect(mapStateToProps, mapDispatchToProps)(Course);

以上代码可以看出,connect实际上是一个函数。生成一个与redux store连接的容器组件。

connect(mapStateToProps, mapDispatchToProps)(Course);

mapStateToProps:从redux状态树种提取需要的部分作为props传递给当前的组件。
mapDispatchToProps: 将需要的action作为props传递给当前的组件。

总结

react-redux是连接react(ui渲染)和redux(store数据管理中心)的桥梁,实现统一的数据管理,从而更优雅的实现数据驱动的一种模式。