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

来源:互联网 发布:blast软件下载 编辑:程序博客网 时间:2024/06/07 20:08

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

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

点到为止了,所以我也就尝试去看了 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,最基本,最简单的写法:


//actionTypeexport const ACTION_TYPE = 'ACTION_TYPE';//actionCreatorlet 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((  <Provider store={store}>   // ...  </Provider>), 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 中获取<div>{this.props.propA}</div>    }}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 的修改,即可完成异步请求。


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




0 0
原创粉丝点击