redux 及 react-redux基本用法及源码解析

 某年某月某日,某师兄说:学一个东西,不能只停留在表面,只知道怎么用是完全不够的,

要清楚的明白,为什么这么做,为什么不那样做,还得从源码开始,虽然起步可能会比较坎坷,毕竟知识储备有限。

点到为止了,所以我也就尝试去看了 redux 以及 react-redux 源码,确实坎坷。

在此对看过的一些资料做一个总结。


先讲讲其基本用法,最后附上源码解析:

其实简单的应用,甚至只是一个单页应用,那完全是用不到 redux 的,只会让代码量提升了却没什么好处,出力不讨好。

redux 不仅仅只限于和 react 搭配使用,它可说是一个数据(state)管理器,也可在其他场景中使用。

当然 react-redux 就顾名思义不是适用于任何场景了。

如果用过 FLUX 的同学,应该会对 redux 的主要思想比较容易理解:

单项数据流,但存在与 FLUX比较大的差别是redux 整个应用只有一个数据源,也就是只有一个 store,在复杂的应用中也统一管理所有的数据。

我觉得 store 是整个 redux 的核心,最为核心的就是 store 的四个 function:

dispatch:分发 Action 到对应的 Reducer后,根据 Reducer 逻辑更改store 中的 state,之后触发 subscribe的 listener,

getState:获取当前store 中的 state 数据,

subscribe: 注册 listener,在 state 变化时触发,

replaceReducer:替换 Reducer,修改 state 变化逻辑,不是很常用。

我们需要做的是创建 store,Action,Reducer,最基本,最简单的写法:


//actionType
export const ACTION_TYPE = 'ACTION_TYPE';
//actionCreator
let actionCreator = (config) => {
    return {
        type: ACTION_TYPE, // 必须定义 type
        config // 可定义任何属性,都会传递到 reducer,用于修改 state
    }
}

action 其实就是一个普通对象,当然你也可以直接写这个对象,但存在诸多劣势。

import { ACTION_A, ACTION_B } from '../actions';
let initialState = { ... }
function example(state = initialState, action) {
    switch(action.type) {
        case ACTION_A:
          return Object.assign({}, state, action.config)
        case ACTION_B:
          return Object.assign({}, state, action.config)
	default:
	  return state
    }
}

reducer 里只做修改state,纯函数

import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux'
import thunk from 'redux-thunk';
import reducers from './reducers';
let store = createStore(reducers);
ReactDOM.render((
  
   // ...
  
), document.querySelector('#app'));

创建一个 store,也是整个应用唯一的 store。

Provider 是 react-redux 中提供的。可以通过Provider将 store 传递到包含在它之内的所有子组件里,但需配合 connect 使用。

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { actionA } from 'actions';
class ComponentA extends Component {
    constructor(props) {
        super(props);
    }
    componentDidMount() {
        let { dispatch } = this.props;
        dispatch(actionA())
    }
    render() {
//由于所用到的 state 都绑定到了 props 中,component 中用到的时候可在 props 中获取
	
{this.props.propA}
} }let mapStateToProps = (state) => { // attention,会把最新的 state 数据绑定到组件 props 中。 //只需绑定和本组件相关的 state 即可(state 是包含了整个应用的所有数据的。 let { reducerA, reducerB } = state; return { propA: reducerA.propA, propB: reducerB.propB } }; export default connect(mapStateToProps)(ComponentA);
connect 也是 react-redux 中提供的,这里简单的介绍下,最基础的用法就是只传mapStateToProps 方法,

返回的是一个包含了调用 getState,subscribe 的原组件(这里即 ComponentA)。

这样就完成一整套简单的 redux 融合的 react 组件应用了。

但这样的数据交互都是同步的,无法支持 ajax 的异步请求。

如果想实现就需要加入 thunk中间件去完成,同时需改造 action,不仅仅是一个简单的普通 Object 即可完成的了。

另一种方法即在 component 中创建store,在 component 内就能直接调用 store.dispatch,store.subscribe,store.getState 等方法,完成数据管理。

但这种写法有个坑,即比如在 componentDidMount中注册了 subscribe 的 listener 时会返回一个 unsubscribe 方法,

用于解绑的,必须在 componentWillUnmount 的时候执行该方法,不然会报警告,在组件卸载时仍在监听。

componentDidMount(){
    self.unsubscribe = subscribe(()=>{xxx});
}
componentWillUnmount(){
    self.unsubscribe();
}

需要异步请求时,需要对 store 和 action 进行改造加强:

export default function configureStore(initialState) {
  const store = createStore(rootReducer,initialState,applyMiddleware(
    thunkMiddleware,//支持异步操作
    createLogger()//输出 redux 的action 和 state相关 log
  ))
  return store;
}
action 需改成根据异步请求不同状态发出不同的 action,包装成一个方法来完成
export function  fetchAction() {
    return dispatch => {
        dispatch({
            type: 'REQUEST_POSTS'
        })
        return fetch(`xxxxx`, {
            method: 'GET',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            }
        })
            .then(response => response.json())
            .then(function (json) {
                if (json.success) {
                    dispatch({
                        type: CATEGORIES_RECEIVE_POSTS,
                        data: json
                    })
                } else {
                    info('数据获取失败,请稍候再试!')
                }
            })
            .catch(e => {
                debugger;
            })
    }
}
直白的理解就是发起请求时发出一个 action(不真实改变 state,只改变请求状态),

请求返回成功一个action,失败一个 action 让 reducer 做出不同的对 state 的修改,即可完成异步请求。


源码解析接下一篇博客哟~




你可能感兴趣的:(学习心得与总结)