快捷搜索:
来自 新京葡娱乐场网址 2019-12-13 21:15 的文章
当前位置: 67677新澳门手机版 > 新京葡娱乐场网址 > 正文

Redux从入门到跳楼,源码剖析及应用

Redux 源码分析及利用

2018/05/23 · JavaScript · Redux

原稿出处: 新浪技能公司   

应用redux react本来就有生龙活虎段时间,刚开头运用未有深远摸底其源码,前段时间静下心细读源码,感触颇深~

本文首要富含Redux设计思想、源码分析、Redux应用实例应用七个方面。

参照链接:

背景:

React 组件 componentDidMount 的时候起始化 Model,并监听 Model 的 change 事件,当 Model 爆发变动时调用 React 组件的 setState 方法重复 render 整个组件,最后在组件 componentWillUnmount 的时候撤除监听并销毁 Model。

最开头落到实处四个粗略实例:比如add加法操作,只须要通过React中 setState 去调整变量扩大的意况,特别轻巧方便。

而是当咱们必要在项目中追加乘法/除法/幂等等复杂操作时,就要求规划八个state来支配views的校订,当项目变大,里面含有状态过多时,代码就变得难以维护而且state的变迁不可预测。恐怕须求扩充三个小效能时,就能够孳生多处改动,导致支出频率减弱,代码可读性不高

比方现在应用超级多backbone方式:新京葡娱乐场网址 1

如上图所示,可以看出 Model 和 View 之间涉及参差不齐,前期代码难以维护。

为了然除上述难点,在 React 中引进了 Redux。Redux 是 JavaScript 状态容器,提供可预测化的处境处理方案。下边详细介绍~~

  • Redux华语文书档案
  • Redux 入门教程-阮生龙活虎峰
  • 看漫画,学 Redux
  • 在react-native中使用redux
  • [React Native]Redux的大旨接收方法
  • Redux管理复杂应用数据逻辑

目的:

1、深远明白Redux的规划观念

2、剖判Redux源码,并结合实际应用对源码有越来越深档期的顺序的领会

3、实际工程应用中所蒙受的难题总结,幸免重新踩坑

目录

  • 利用途景
  • 运用的三标准
    • 纯净数据源
    • 景况是只读的
    • 经过纯函数修正State
  • redux状态管理的流水生产线及连锁概念
    • store
    • Action
    • Action 成立函数(Action Creator卡塔尔(英语:State of Qatar)
    • Reducer
  • redux如何与组件结合
    • 切切实实示例1
    • 实际示例2

风度翩翩、Redux设计理念

接纳场景

React设计观念之生机勃勃为单向数据流,那从大器晚成边方便了数码的管住。但是React自个儿只是view,并未提供康健的多少管理方案。随着应用的持续复杂化,假使用react营造前端接受的话,就要应对纷纭复杂的数量通讯和扣押,js供给保护越来越多的处境(state),这一个state大概富含客商新闻、缓存数据、全局设置情形、被激活的路由、被选中的标签、是不是加载动作效果或然分页器等等。

此刻,Flux构造应时而生,Redux是其最文雅的完结,Redux是三个不注重任何库的框架,不过与react结合的最佳,个中react-redux等开源组件正是把react与redux组合起来进行调用开垦。

备注:

1.假如您不清楚是不是必要 Redux,那便是没有须要它

2.只有蒙受 React 实在解除不了的主题素材,你才需求 Redux

Redux使用处境:

  • 某些组件的气象,需求分享
  • 某些状态需求在另各地点都得以得到
  • 一个零部件须要更动全局状态
  • 三个零零件供给改动另三个零零件的处境

比如,论坛应用中的夜晚设置、回到最上端、userInfo全局分享等气象。redux最后指标正是让景况(state卡塔尔(英语:State of Qatar)变化变得可预测.

背景:

理念 View 和 Model :一个 view 只怕和四个 model 相关,三个 model 也说倒霉和多少个 view 相关,项目复杂后代码耦合度太高,难以维护。

redux 应际而生,redux 中着力概念reducer,将具有复杂的 state 集中管理,view 层客户的操作不可能一贯改动 state进而将view 和 data 解耦。redux 把古板MVC中的 controller 拆分为action和reducer

应用的三准则

  • 单纯性数据源

整套应用的state,存款和储蓄在唯少年老成二个object中,同一时间也唯有二个store用于存款和储蓄这么些object.

  • 状态是只读的

唯生龙活虎能改造state的格局,便是触发action操作。action是用来说述正在发生的平地风波的三个对象

  • 通过纯函数修改State

纯函数的主题素材,也是源于于函数式编制程序观念,我们在中学时学的函数便是纯函数,对于同一个输入,必然有平等的出口。那就确定保证了多少的可控性,这里的纯函数正是reducer

设计理念:

(1)Web 应用是二个状态机,视图与气象是逐生机勃勃对应的。

(2)全体的情事,保存在三个对象里面。

Redux 让使用的状态变化变得可预测。要是想改换使用的动静,就亟须 dispatch 对应的 action。而不可能一贯改造使用的气象,因为保存这几个情形的地点(称为 store)只有 get方法(getState) 而没有 set方法

如果Redux 订阅(subscribe卡塔尔(英语:State of Qatar)相应框架(举例React卡塔尔(قطر‎内部方法,就足以采用该应用框架保险数据流动的黄金时代致性。

redux状态管理的流水生产线及相关概念

新京葡娱乐场网址 2

image

  • store

Store 便是保存数据的地点,保存着本程序有所的redux管理的多寡,你能够把它作为一个容器。整个应用只好有叁个Store。(四个store是叁个对象, reducer会改换store中的有些值卡塔尔(قطر‎

Redux 提供createStore那么些函数,用来生成 Store。

import { createStore } from 'redux';
const store = createStore(fn);

下边代码中,createStore函数选取另四个函数作为参数,重临新生成的 Store 对象。那个fn就是reducer纯函数,平日大家在支付中也会动用中间件,来优化结构,譬如最常用的异步操作插件,redux-thunk,假设相配redux-thunk来创制store的话,代码示例:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers/rootReudcer';

let createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
let store = createStoreWithMiddleware(rootReducer);

redux-thunk的源码及其轻松,如下:

// 判断action是否是函数,如果是,继续执行递归式的操作。所以在redux中的异步,只能出现在action中,而且还需要有中间件的支持。
function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

同步action与异步action最大的区别是:

协同只回去一个普通action对象。而异步操作中途会重临一个promise函数。当然在promise函数管理达成后也会回到三个普通action对象。thunk中间件正是推断如若回去的是函数,则不传导给reducer,直到检测到是普通action对象,才交由reducer管理。


新京葡娱乐场网址 ,Store 有以下职责:

  • 提供 getState(卡塔尔国 方法得到 state;
  • 提供 dispatch(action卡塔尔国 方法立异 state;
  • 经过 subscribe(listener卡塔尔国 注册监听器;
  • 由此 subscribe(listener卡塔尔(英语:State of Qatar) 再次来到的函数注销监听器。

诚如情况下,大家只必要getState(卡塔尔和dispatch(卡塔尔国方法就能够,即能够缓和绝超越八分之四主题素材。

咱俩得以自定义中间件

比如我们自定义叁个方可打字与印刷出近日的接触的action以致出发后的state变化的中间件,代码改正如下:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers/rootReudcer';

let logger = store => next => action => {
    if(typeof action === 'function') {
        console.log('dispatching a function')
    }else{
        console.log('dispatching', action);
    }

    let result = next(action);
    // getState() 可以拿到store的状态, 也就是所有数据
    console.log('next state', store.getState());
    return result;
}

let middleWares = {
    logger, 
    thunk
}
// ... 扩展运算符
let createStoreWithMiddleware = applyMiddleware(...middleWares)(createStore);

let store = createStoreWithMiddleware(rootReducer);

补偿:大家自定义的中间件,也许有对应的开源插件,redux-logger,人家的更决定。

万意气风发,app中关系到登陆难题的时候,能够利用redux-persist其三方插件,那一个第三方插件来将store对象存款和储蓄到当地,以至从本土复苏数据到store中,举例说保存登入消息,下一次张开应用能够平素跳过登入界面,因为大家脚下的利用归属内嵌程序,不登录的话也进不来,所以不要它。

  • Action

Action 是叁个目的,描述了接触的动作,如此而已。大家约定,action 内必得采纳三个字符串类型的 type 字段来代表将在实行的动作。平日它长一下那么些样子:

{
  type: ADD_TODO,
  text: 'Build my first Redux app'
}

除开 type 字段外,action 对象的布局完全由你自身说了算,来看一个复杂点的:

{
    type: 'SET_SCREEN_LAST_REFRESH_TIME',
    screenId,
    lastRefreshTime,
    objectId
}

习感到常大家会增多叁个新的模块文件来积攒那个actions types,比方大家新建二个actionTypes.js来保存:

//主页actions
export const FETCH_HOME_LIST = 'FETCH_HOME_LIST';
export const RECEIVE_HOME_LIST = 'RECEIVE_HOME_LIST';
//分类页actions
export const FETCH_CLASS_LIST = 'FETCH_CLASS_LIST';
export const RECEIVE_CLASS_LIST = 'RECEIVE_CLASS_LIST';
//分类详细页actions
export const FETCH_CLASSDITAL_LIST = 'FETCH_CLASSDITAL_LIST';
export const RECEIVE_CLASSDITAL_LIST = 'RECEIVE_CLASSDITAL_LIST';
export const RESET_CLASSDITAL_STATE = 'RESET_CLASSDITAL_STATE'; 
// 设置页actions
export const CHANGE_SET_SWITCH = 'CHANGE_SET_SWITCH';
export const CHANGE_SET_TEXT = 'CHANGE_SET_TEXT';
// 用户信息
export const USER_INFO = 'USER_INFO';

引用的时候,能够:

import * as types from './actionTypes';
  • Action 创立函数(Action Creator卡塔尔国

Action 创设函数 正是生成 action 的主意。“action” 和 “action 创造函数” 那七个概念超轻易混在一块儿,使用时最棒注意区分。在 Redux 中的 action 创设函数只是简短的回来二个 action。

import * as types from './actionTypes';
// 设置详情页内容文字主题
let changeText = (theme) => {
    return {
        type: types.CHANGE_SET_TEXT,
        theme
    }
}   

// 函数changeText就是一个简单的action creator。

完整的action文件(setAction.js)

import * as types from './actionTypes';

let setTitle = (value) => {
    return (dispatch, getState) => {
        dispatch(changeValue(value))
    }
}

let setText = (text) => {
    return dispatch => {
        dispatch(changeText(text))
    }
}

// 修改标题颜色主题
let changeValue = (titleTheme) => {
    return {
        type: types.CHANGE_SET_SWITCH,
        titleTheme
    }
}

// 设置详情页内容文字颜色
let changeText = (textColor) => {
    return {
        type: types.CHANGE_SET_TEXT,
        textColor
    }
}

export {
    setText,
    setTitle
};

能够看看上述setTitle、setText函数,重返的并非三个action对象,而是回到了叁个函数,那个暗许redux是无可奈何管理的,这就须要运用中间件管理了,redux-thunk中间件用于拍卖回来函数的函数,上边也介绍了redux-thunk的运用基本办法。

  • Reducer

Store 收到 Action 未来,必得提交七个新的 State,那样 View 才会产生变化。这种 State 的思量进度就称为 Reducer。
Reducer 是三个函数,它选择 Action 和近来 State 作为参数,重回多少个新的 State。

函数具名:

(previousState, action) => newState

Reducer必需保障相对十足,永久不要在 reducer 里做那几个操作:

  • 更正传入参数;
  • 实施有副效率的操作,如 API 须求和路由跳转;
  • 调用非纯函数,如 Date.now(卡塔尔(英语:State of Qatar) 或 Math.random(卡塔尔国;

完整的Reducer方法,(setReducer.js):

import * as types from '../actions/actionTypes';

const initialState = {
    titleTheme: false,
    textColor: false
}
// 这里一个技巧是使用 ES6 参数默认值语法 来精简代码
let setReducer = (state = initialState, action) => {

    switch(action.type){
        case types.CHANGE_SET_SWITCH:
            return Object.assign({}, state, {
                titleTheme: action.titleTheme,
            })

        case types.CHANGE_SET_TEXT:
            return Object.assign({}, state, {
                textColor: action.textColor
            })

        default:
            return state;
    }
}

export default setReducer

注意:

  • 决不改换 state。 使用 Object.assign(卡塔尔(英语:State of Qatar) 新建了一个别本。不能够那样使用 Object.assign(state, {
    titleTheme: action.titleTheme,
    }卡塔尔(英语:State of Qatar),因为它会转移第一个参数的值。你不得不把第一个参数设置为空对象。你也得以张开对ES7议案对象实行运算符的支撑, 进而使用 { ...state, ...newState } 达到相似的目标。
  • 在 default 景况下回到旧的 state。遭受未知的 action 时,必必要赶回旧的 state

关于拆分Reducer

此处只是比喻了三个粗略的成效的reducer,如若有例外的功用,供给规划超级多reducer方法,注意每个reducer 只担负管理全局 state 中它担任的生机勃勃有的。每一种 reducer 的 state 参数都不可以偏概全,分别对应它管理的这有个别 state 数据。

举例我们以此类型的reducer文件布局:

新京葡娱乐场网址 3

image.png

内部rootReducer.js就是多少个根reducer文件,使用了Redux 的 combineReducers() 工具类来张开包装整合。

/**
 * rootReducer.js
 * 根reducer
 */
import { combineReducers } from 'redux';
import Home from './homeReducer';
import Class from './classReducer';
import ClassDetial from './classDetialReducer';
import setReducer from './setReducer';
import userReducer from './userReducer';

export default rootReducer = combineReducers({
    Home,
    Class,
    ClassDetial,
    setReducer,
    userReducer,
})

如此依据那个根reducer,可以生成store,请看上文store的始建进程。

Action Creator:

只可以通过dispatch action来改造state,那是并世无双的艺术

action平日的款式是: action = { type: ‘ … ‘, data: data } action一定是有三个type属性的对象

在dispatch任何叁个 action 时将具备订阅的监听器都实践,公告它们有state的校订新京葡娱乐场网址 4

redux如何与组件结合

以上部分介绍了Redux 涉及的基本概念,上面介绍与组件交互作用的干活流程。

梳理一下Redux的行事流程:

新京葡娱乐场网址 5

image

1.第风华正茂,客商产生 Action。

store.dispatch(action);

2.Store 机动调用 Reducer,况且传入五个参数:当前 State 和收受的 Action。 Reducer 会重临新的 State 。

let nextState = todoApp(previousState, action);

3.state意气风发旦有变化,Store就能够调用监听函数,组件能够感知state的变动,更新View。

let newState = store.getState();
component.setState(newState);

具体示例1:

新京葡娱乐场网址 6

fsdf.gif

安装页面有个switch按键,能够全局设置标题栏的大旨。

Store:

Redux中独有三个store,store中保留应用的富有景况;判定需求改造的景况分配给reducer去管理。

可以有两个reducer,每一种reducer去承受一小部分意义,最终将四个reducer归拢为三个根reducer

作用:

  • 维持state树;
  • 提供 getState(卡塔尔 方法获得 state;
  • 提供 dispatch(action卡塔尔(英语:State of Qatar) 方法改正 state;
  • 由此 subscribe(listener卡塔尔 注册监听器。
代码拆分:

1.设置按键所在组件:

// SetContainer.js

import React from 'react';
import {connect} from 'react-redux';
import SetPage from '../pages/SetPage';

class SetContainer extends React.Component {
    render() {
        return (
            <SetPage {...this.props} />
        )
    }
}

export default connect((state) => {

    const { setReducer } = state;
    return {
        setReducer
    }

})(SetContainer);

那是容器组件,将SetPage组件与redux结合起来,个中最重要的诀假若connect,这一个示例中是将setReducer作为品质传给SetPage组件,关于connect的详细明白,请移步到connect()。

2.SetPage组件

import React, {
    Component
} from 'react';
import {
    StyleSheet,
    Text,
    Image,
    ListView,
    TouchableOpacity,
    View,
    Switch,
    InteractionManager,
} from 'react-native';

import Common from '../common/common';
import Loading from '../common/Loading';
import HeaderView from '../common/HeaderView';

import {setText,setTitle} from '../actions/setAction';

export default class SetPage extends Component {
    constructor(props){
        super(props);
        this.state = {
            switchValue: false,
            textValue: false
        }

        this.onValueChange = this.onValueChange.bind(this);
        this.onTextChange = this.onTextChange.bind(this);
    }

    componentDidMount() {
        // console.log(this.props)
    }

    onValueChange(bool) {
        const { dispatch } = this.props;
        this.setState({
            switchValue: bool
        })
        dispatch(setTitle(bool));
    }

    onTextChange(bool) {
        const { dispatch } = this.props;

        this.setState({
            textValue: bool
        });

        dispatch(setText(bool));
    }

    render() {
        return (
            <View>
                <HeaderView
                  titleView= {'设置'}
                  />

                <View>
                    <View style={styles.itemContainer}>
                        <Text style={{fontSize: 16}}>全局设置标题主题</Text>
                        <Switch 
                            onValueChange={this.onValueChange}
                            value={this.state.switchValue}
                        />
                    </View>

                    <View style={styles.itemContainer}>
                        <Text style={{fontSize: 16}}>设置详情页文字主题</Text>
                        <Switch 
                            onValueChange={this.onTextChange}
                            value={this.state.textValue}
                        />
                    </View>
                </View>
            </View>
        )
    }
}

const styles = StyleSheet.create({
    itemContainer:{
        paddingLeft: 20,
        paddingRight: 20,
        height: 40,
        flexDirection: 'row',
        justifyContent: 'space-between',
        alignItems: 'center'
    }
})

能够只看全局设置题目大旨那一个艺术,设置详细情形页文字颜色和他同理。这里可以清晰的观看,客户切换大旨switch按键的时候,触发的点子:

dispatch(setTitle(bool));

3.大家查阅一下setTitle那一个action的源码:

// setAction.js
import * as types from './actionTypes';

let setTitle = (value) => {
    return (dispatch, getState) => {
        dispatch(changeValue(value))
    }
}

let setText = (text) => {
    return dispatch => {
        dispatch(changeText(text))
    }
}

// 修改标题主题
let changeValue = (titleTheme) => {
    return {
        type: types.CHANGE_SET_SWITCH,
        // 这里将titleTheme状态返回
        titleTheme
    }
}

// 设置详情页内容文字主题
let changeText = (textColor) => {
    return {
        type: types.CHANGE_SET_TEXT,
        textColor
    }
}

export {
    setText,
    setTitle
};

4.action只是担当发送事件,并不会重临八个新的state供页面组件调用,它是在reducer中回到的:

// setReducer.js

import * as types from '../actions/actionTypes';

const initialState = {
    titleTheme: false,
    textColor: false
}

let setReducer = (state = initialState, action) => {

    switch(action.type){
        case types.CHANGE_SET_SWITCH:
            return Object.assign({}, state, {
                titleTheme: action.titleTheme,
            })

        case types.CHANGE_SET_TEXT:
            return Object.assign({}, state, {
                textColor: action.textColor
            })

        default:
            return state;
    }
}

export default setReducer

最简便的reducer,正是基于领头值和action对象,再次回到二个新的state,提要求store,那样,页面里能够从store中获取到那么些全局的state,用于更新组件。

我们只是写了怎么发送action和选择action发出newState的,上面来看这一个标题组件是何许和redux结合的。

5.HeaderView组件

/**
 * Created by ljunb on 16/5/8.
 * 导航栏标题
 */
import React from 'react';
import {
    StyleSheet,
    View,
    Text,
    Image,
    TouchableOpacity,
} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import Common from '../common/common';
import {connect} from 'react-redux';

class HeaderView extends React.Component {

    constructor(props){
        super(props);

        this.state = {

        }
    }

    render() {
        // 这里,在这里
        const { titleTheme } = this.props.setReducer;
        let NavigationBar = [];

        // 左边图片按钮
        if (this.props.leftIcon != undefined) {
            NavigationBar.push(
                <TouchableOpacity
                    key={'leftIcon'}
                    activeOpacity={0.75}
                    style={styles.leftIcon}
                    onPress={this.props.leftIconAction}
                    >
                    <Icon color="black" size={30} name={this.props.leftIcon}/>
                </TouchableOpacity>
            )
        }

        // 标题
        if (this.props.title != undefined) {
            NavigationBar.push(
                <Text key={'title'} style={styles.title}>{this.props.title}</Text>
            )
        }

        // 自定义标题View
        if (this.props.titleView != undefined) {
            let Component = this.props.titleView;

            NavigationBar.push(
                <Text key={'titleView'} style={[styles.titleView, {color: titleTheme ? '#FFF' : '#000'}]}>{this.props.titleView}</Text>
            )
        }


        return (
            <View style={[styles.navigationBarContainer, {backgroundColor: titleTheme ? 'blue' : '#fff'}]}>
                {NavigationBar}
            </View>
        )
    }
}

const styles = StyleSheet.create({

    navigationBarContainer: {
        marginTop: 20,
        flexDirection: 'row',
        height: 44,
        justifyContent: 'center',
        alignItems: 'center',
        borderBottomColor: '#ccc',
        borderBottomWidth: 0.5,
        backgroundColor: 'white'
    },

    title: {
        fontSize: 15,
        marginLeft: 15,
    },
    titleView: {
        fontSize: 15,
    },
    leftIcon: {
       left: -Common.window.width/2 40,
    },
})


export default connect((state) => {

    const { setReducer } = state;
    return {
        setReducer
    }

})(HeaderView);

其后生可畏组件相仿应用connect方法绑定了redux,形成了容器组件(container component)。

connect真的很首要,请详细查看官方文书档案,下面有链接。

任何不相干的内容忽视,大旨代码是:

// 拿到全局的state 当有变化的时候,会马上修改
const { titleTheme } = this.props.setReducer;

现实示例2:

新京葡娱乐场网址 7

image.png

动用redux来乞求数据、下拉刷新、上拉加载越来越多。

1.首先,封装action。

import * as types from './actionTypes';
import Util from '../common/utils'; 
// action创建函数,此处是渲染首页的各种图片
export let home = (tag, offest, limit, isLoadMore, isRefreshing, isLoading) => {
    let URL = 'http://api.huaban.com/fm/wallpaper/pins?limit=';
    if (limit) URL  = limit;
    offest ? URL  = '&max='   offest : URL  = '&max=';
    tag ? URL  = '&tag='   encode_utf8(tag) : URL  = '&tag='

    return dispatch => {
        // 分发事件  不修改状态   action是 store 数据的唯一来源。
        dispatch(feachHomeList(isLoadMore, isRefreshing, isLoading));
        return Util.get(URL, (response) => {
            // 请求数据成功后
            dispatch(receiveHomeList(response.pins))
        }, (error) => {
            // 请求失败
            dispatch(receiveHomeList([]));
        });

    }

}

function encode_utf8(s) {
    return encodeURIComponent(s);
}

// 我们约定,action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作。
let feachHomeList = (isLoadMore, isRefreshing, isLoading) => {
    return {
        type: types.FETCH_HOME_LIST,
        isLoadMore: isLoadMore,
        isRefreshing: isRefreshing,
        isLoading: isLoading,
    }
}

let receiveHomeList = (homeList) => {
    return {
        type: types.RECEIVE_HOME_LIST,
        homeList: homeList,
    }
}
  • feachHomeList表示正在呼吁数据的动作;
  • receiveHomeList表示央浼数据完后的动作;
  • dispatch(feachHomeList(isLoadMore, isRefreshing, isLoading卡塔尔(قطر‎卡塔尔;表示分发央求数据的动作;

2.封装reducer函数

import * as types from '../actions/actionTypes';
// 设置初始状态
const initialState = {
    HomeList: [],
    isLoading: true,
    isLoadMore: false,
    isRefreshing: false,
};

let homeReducer = (state = initialState, action) => {

    switch (action.type) {
        case types.FETCH_HOME_LIST:
            return Object.assign({}, state, {
                isLoadMore: action.isLoadMore,
                isRefreshing: action.isRefreshing,
                isLoading: action.isLoading
            })

        case types.RECEIVE_HOME_LIST:
            // 如果请求成功后,返回状态给组件更新数据
            return Object.assign({}, state, {
            // 如果是正在加载更多,那么合并数据
                HomeList: state.isLoadMore ? state.HomeList.concat(action.homeList) : action.homeList,
                isRefreshing: false,
                isLoading: false,
            })

        case types.RESET_STATE: // 清除数据
            return Object.assign({},state,{
                HomeList:[],
                isLoading:true,
            })
        default:
            return state;
    }
}

export default homeReducer;
  • 那边并从未拍卖未有更超级多据的气象。

3.容器组件

import React from 'react';
import {connect} from 'react-redux';
import Home from '../pages/Home';

class HomeContainer extends React.Component {
    render() {
        return (
            <Home {...this.props} />
        )
    }
}

export default connect((state) => {
    const { Home } = state;
    return {
        Home
    }
})(HomeContainer);
  • 那边最首纵然应用connect函数将Home state绑定到Home组件中,并作为它的props;

4.UI组件

  • 组件挂载恳求数据
...
let limit = 21;
let offest = '';
let tag = '';
let isLoadMore = false;
let isRefreshing = false;
let isLoading = true;
...
componentDidMount() {
    InteractionManager.runAfterInteractions(() => {
      const {dispatch} = this.props;
      // 触发action 请求数据
      dispatch(home(tag, offest, limit, isLoadMore, isRefreshing, isLoading));
    })
}
...
  • 下拉刷新
// 下拉刷新
  _onRefresh() {
    if (isLoadMore) {
      const {dispatch, Home} = this.props;
      isLoadMore = false;
      isRefreshing = true;
      dispatch(home('', '', limit, isLoadMore, isRefreshing, isLoading));
    }
  }
  • 上拉加载越多
// 上拉加载
  _onEndReach() {

    InteractionManager.runAfterInteractions(() => {
      const {dispatch, Home} = this.props;
      let homeList = Home.HomeList;
      isLoadMore = true;
      isLoading = false;
      isRefreshing = false;
      offest = homeList[homeList.length - 1].seq
      dispatch(home(tag, offest, limit, isLoadMore, isRefreshing, isLoading));
    })

  }
  • render方法
render() {
    // 这里可以拿到Home状态
    const { Home,rowDate } = this.props;
     tag = rowDate;

    let homeList = Home.HomeList;
    let titleName = '最新';
    return (
      <View>
        <HeaderView
          titleView= {titleName}
          leftIcon={tag ? 'angle-left' : null}
          />
        {Home.isLoading ? <Loading /> :
          <ListView
            dataSource={this.state.dataSource.cloneWithRows(homeList) }
            renderRow={this._renderRow}
            contentContainerStyle={styles.list}
            enableEmptySections={true}
            initialListSize= {10}
            onScroll={this._onScroll}
            onEndReached={this._onEndReach.bind(this) }
            onEndReachedThreshold={10}
            renderFooter={this._renderFooter.bind(this) }
            style={styles.listView}
            refreshControl={
              <RefreshControl
                refreshing={Home.isRefreshing}
                onRefresh={this._onRefresh.bind(this) }
                title="正在加载中……"
                color="#ccc"
                />
            }
            />
        }
      </View>

    );

  }

由来,三个简约的Reducer程序完毕了,大家有一些总括一下:

  • 全部应用独有多个store,用来保存全体的景况,视图无需团结维护状态。
  • 视图通过connect函数绑定到store,当store状态变化后,store会布告视图刷新。
  • 接触三个action之后,会透过大概N个reducers管理,最终根reducer会将富有reducers管理以往的气象合併,然后交由store,store再布告视图刷新。

正文的源码地址: 案例Demo

Reducer:

store想要知道一个action触发后什么转移状态,会施行reducer。reducer是纯函数,根reducer拆分为多少个小reducer ,每种reducer去管理与自己相关的state更新

注:不直接改变总体应用的景色树,而是将状态树的每生龙活虎部分开展拷贝并改过拷贝后的变量,然后将那些部分重新整合成后生可畏颗新的景况树。运用了数码不可变性(immutable),易于跟踪数据变动。别的,还足以追加比方注销操作等功能。

Views:

容器型组件 Container component 和显示型组件 Presentational component)

提出是只在最顶层组件(如路由操作)里应用 Redux。其他内部零零器件仅仅是体现性的,全部数据都因此 props 传入。

容器组件 展示组件
Location 最顶层,路由处理 中间和子组件
Aware of Redux
读取数据 从 Redux 获取 state 从 props 获取数据
修改数据 向 Redux 派发 actions 从 props 调用回调函数

Middleware:

中间件是在action被提倡之后,到达reducer以前对store.dispatch方法开展扩张,加强其效果。

举例常用的异步action => redux-thunk、redux-promise、redux-logger等

Redux中store、action、views、reducers、middleware等数码流程图如下:新京葡娱乐场网址 8

简化数据流程图:新京葡娱乐场网址 9

Redux核心:

  • 纯净数据源,即:整个Web应用,唯有贰个Store,存款和储蓄着独具的数量【数据布局嵌套太深,数据访谈变得繁杂】,保障一切数据流程是Predictable。
  • 将三个个reducer自上而下拔尖顶尖地统一齐,最终获得贰个rootReducer。 => Redux通过三个个reducer完毕了对一切数据源(object tree)的拆除与搬迁访谈和纠正。 => Redux通过三个个reducer完结了不可变数据(immutability)。
  • 具备数据都是只读的,不可能修正。想要改过只可以透过dispatch(action卡塔尔(قطر‎来退换state。

二、Redux源码剖判

前记— redux的源码相比直观简洁~

Redux概念和API,请直接查看官方斯洛伐克语API和法定普通话API

Redux目录布局:

|---src   |---applyMiddleware.js   |---bindActionCreators.js   |---combineReducers.js   |---compose.js   |---createStore.js 定义createStore   |---index.js redux主文件,对外暴露了多少个为主API

1
2
3
4
5
6
7
|---src
  |---applyMiddleware.js
  |---bindActionCreators.js
  |---combineReducers.js
  |---compose.js
  |---createStore.js 定义createStore
  |---index.js redux主文件,对外暴露了几个核心API

以下分别是逐个文件源码解析(带汉语讲解卡塔尔:

1) combineReducers.js

  • 真相:组合八个分支reducer并重返多少个新的reducer,参数也是state和action,实行state的翻新管理
  • 早先化:store.getState(卡塔尔(英语:State of Qatar)的开首值为reducer(initialState, { type: ActionTypes.INIT }卡塔尔(قطر‎
  • Reference:

新京葡娱乐场网址 10

combineReducers(卡塔尔(قطر‎所做的只是生成三个函数,这几个函数来调用风华正茂多种reducer,每种reducer依照它们的key来筛选出state中的黄金时代有个别数据并拍卖,然后那一个调换的函数再将有所reducer的结果归并成多个提及底的state对象。

在其实使用中,reducer中对于state的管理是后来成四个state对象(深拷贝):新京葡娱乐场网址 11

从而在combineReducers中各类小reducers的 nextStateForKey !== previousStateForKey 一定为 true => hasChange也一定为true

那就是说难点来了,为何要每一回都拷贝八个新的state,再次来到一个新的state呢?
解释:
  1. Reducer 只是一些纯函数,它选用以前的 state 和 action,并再次回到新的 state。刚初始容许独有叁个 reducer,随着应用变大,把它拆成三个小的 reducers,分别独立地操作 state tree 的不等部分,因为 reducer 只是函数,能够调节它们被调用的依次,传入附加数据,以致编写可复用的 reducer 来管理部分通用义务,如分页器等。因为Reducer是纯函数,因而在reducer内部直接更改state是副效率,而回到新值是纯函数,可信赖性加强,便于追踪bug。
  2. 除此以外由于不可变数据布局总是改正援引,指向同四个数据布局树,并不是直接改革数据,能够保存大肆四个历史场合,那样就足以产生react diff进而局地刷新dom,也等于react相当流行速的缘由。
  3. 因为严厉界定函数纯度,所以每一个action做了哪些和平谈判会议做哪些总是永恒的,以致足以把action存到多个栈里,然后逆推出早前的有所state,即react dev tools的行事规律。再提起react,日常的话操作dom只好通过副成效,可是react的组件都以纯函数,它们总是被动地平昔表现store中得内容,也正是说,好的机件,不受外界遭受苦闷,长久是牢靠的,出了bug只好在外场的逻辑层。那样写好纯的virtual dom组件,交给react管理副功能,很好地分手了关心点。

本文由67677新澳门手机版发布于新京葡娱乐场网址,转载请注明出处:Redux从入门到跳楼,源码剖析及应用

关键词: