内容简介:简单概述:react-readux中 通过
redux
运行流程图:
简单概述: click -> store.dispatch(action) -> reduer -> newState -> viewUpdate
react-readux中 通过 connect 链接组件和 redux , **this.props.dispatch()**调用
后面将会讲到...
redux
依赖包也是十分的简洁
demo
const redux = require('redux') const createStore = redux.createStore const types = { UPDATE_NAME: 'UPDATE_NAME' } const defaultStore = { user: 'tom' } /** * reducer 纯函数 接收一个state,返回一个新的state * @param {Object} state * @param {Object} action [type] 必选参数 * @return newState * */ function getUser(state = defaultStore, action) { const { type, payload } = action let res = Object.assign({}, defaultStore) switch (type) { case types.UPDATE_NAME: res.user = payload.name break default: return res } return res } const store = createStore(getUser) /** * listener * */ store.subscribe(() => { console.log(store.getState()) }) /** * dispatch(action) action * */ store.dispatch({ type: types.UPDATE_NAME, payload: { name: '大帅哥' } }) //@log { name: '大帅哥' } 复制代码
- 用户发出
action
【store.dispatch(action)
】 -
Store
自动调用Reducer
, 返回新的state
【let nextState = getUser(previousState, action)
】 -
State
一旦有变化,Store
就会调用监听函数 【store.subscribe(listener)
】
运行过程如下:
store
Store
就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store
常用方法:
- store.dispatch() :分发 action 较为常用
- store.subscribe() : state 发生变化后立即执行
- store.getState() : 获取store 中存着的state
createStore
createStore 如其名,创建 store
下面是该方法的部分源码:
/** * @param {Function} reducer 函数 * @param {any} [preloadedState] The initial state * @param {Function} [enhancer] The store enhancer * @returns {Store} * */ export default function createStore(reducer, preloadedState, enhancer) { if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { enhancer = preloadedState preloadedState = undefined } if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.') } return enhancer(createStore)(reducer, preloadedState) } // ... return { dispatch, // 分发 action subscribe, // 监听器 getState, // 获取 store 的 state 值 replaceReducer, [$$observable]: observable // 供Redux内部使用 } } 复制代码
-
preloadedState
: 初始化的initialState
,第二个参数不是Object
,而是Function
,createStore
会认为你忽略了preloadedState
而传入了一个enhancer
-
createStore
会返回enhancer(createStore)(reducer, preloadedState)
的调用结果,这是常见高阶函数的调用方式。在这个调用中enhancer
接受createStore
作为参数,对createStore
的能力进行增强,并返回增强后的createStore
dispatch(action)
diapatch
是store对象的方法,主要用来分发 action
,
redux规定action一定要包含一个type属性,且type属性也要唯一
dispatch 是 store 非常核心的一个方法,也是我们在应用中最常使用的方法,下面是dispatch的源码 :
function dispatch(action) { if (!isPlainObject(action)){ // 校验了action是否为一个原生js对象 throw new Error( 'Actions must be plain objects. ' + 'Use custom middleware for async actions.' ) } if (typeof action.type === 'undefined') { // action对象是否包含了必要的type字段 throw new Error( 'Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?' ) } if (isDispatching) {// 判断当前是否处于某个action分发过程中, 主要是为了避免在reducer中分发action throw new Error('Reducers may not dispatch actions.') } try { isDispatching = true currentState = currentReducer(currentState, action) } finally { isDispatching = false } const listeners = (currentListeners = nextListeners) for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() } // 在一系列检查完毕后,若均没有问题,将当前的状态和action传给当前reducer,用于生成新的state return action } 复制代码
reducer && store.replaceReducer
Redux中负责响应action并修改数据的角色就是 reducer
, reducer
的本质实际上是一个函数 replaceReducer:
/** * @desc 替换当前的reducer的函数 * @param {Function} * @return {void} */ function replaceReducer(nextReducer) { if (typeof nextReducer !== 'function') { throw new Error('Expected the nextReducer to be a function.') } currentReducer = nextReducer dispatch({ type: ActionTypes.REPLACE }) } 复制代码
replaceReducer 使用场景:
- 当你的程序要进行代码分割的时候
- 当你要动态的加载不同的reducer的时候
- 当你要实现一个实时reloading机制的时候
中间件 middleware
以上介绍了redux的实现流的过程,应用场景无非于
button -- click --> disptch
-- action --> reducer
-- newState --> view
但是这种实现方式是基于同步的方式的,日常开发中当然少不了 http 这些异步请求,这种情况下必须等到服务器数据返回后才重新渲染 view, 显然某些时候回阻塞页面的展示。
举例来说,要添加日志功能,把 Action
和 State
打印出来,可以对store.dispatch进行如下改造。
let next = store.dispatch; store.dispatch = function dispatchAndLog(action) { console.log('dispatching', action); next(action); console.log('next state', store.getState()); } 复制代码
上面代码中,对store.dispatch进行了重定义,在发送 Action 前后添加了打印功能。这就是中间件的雏形。
中间件就是一个函数,对store.dispatch方法进行了改造,在发出 Action 和执行 Reducer 这两步之间,添加了其他功能。
applyMiddleware
Redux提供了 applyMiddleware
来装载 middleware
: 它是 Redux 的原生方法,**作用是将所有中间件组成一个数组,依次执行。**下面是它的源码。
/** * @param {...Function} middlewares * returns {Function} A store enhancer applying the middleware */ export default function applyMiddleware(...middlewares) { return createStore => (...args) => { const store = createStore(...args) let dispatch = () => { throw new Error( `Dispatching while constructing your middleware is not allowed. ` + `Other middleware would not be applied to this dispatch.` ) } const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } const chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } } } 复制代码
所有中间件被放进了一个数组chain,然后嵌套执行,最后执行store.dispatch。可以看到,中间件内部(middlewareAPI)可以拿到 getState
和 dispatch
这两个方法
compose
实际上是函数式编程中的组合,接收多个函数体并且将其组合成一个新的函数,例如 compose
后 [fn1, fn2...] 依次从右到左嵌套执行函数 而 compose
用于 applyMiddleware
也是为了组合中间件 dispatch = compose(...chain)(store.dispatch) ==> dispatch=fn1(fn2(fn3(store.dispatch)))
/** * @param {...Function} funcs The functions to compose. * @returns {Function} A function obtained by composing the argument functions */ export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (...args) => a(b(...args))) } 复制代码
redux-thunk
上面的中间件的介绍可以知道 redux 通过 applyMiddleware
来装载中间件,通过compose 方法可以组合函数
异步的问题可以通过 redux-thunk
解决,用法也不难 react 组件中使用相关如下:
// 配置 redux 加上这个... import { createStore, applyMiddleware, compose } from 'redux' import thunk from 'redux-thunk' // ... const store = createStore(getUser, compose( applyMiddleware(thunk) )) // react 中使用 import { connect } from 'react-redux' handleClick = () => { this.props.dispatch( dispatch => { return axios.get('https://randomuser.me/api/').then( res => { dispatch({ type: types.CHANGE_ARRAY, payload: { name: res.data.results[0].name.title } }) } ) } ) } const mapStateToProps = (state, props) => { return { name: state.demo.name } } export default connect( mapStateToProps )(Demo) 复制代码
处理异步的还有很多插件 如 redux-soga 等,楼主并未实践过,所以不做延伸...
react-redux
下面是在react中使用的代码的雏形:
import { createStore } from 'redux' let defaultState = { count: 1 } /** * Reducer * */ function demoReducer(state = defaultState, action = {}) { const { type, payload } = action const res = Object.assign({}, state) if (type === 'changeCount') { res.count = payload.count } return res } /** * @Store 存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store。 * combineReducers({ ...reducers }) 可以组合多个reducer * */ const store = createStore( demoReducer, window.devToolsExtension && window.devToolsExtension() // 配置redux 开发工具 ) // ... 根元素下配置下 Provider import { Provider } from 'react-redux' ReactDOM.render( <Provider store={store}> <App/> </Provider>, document.getElementById('root') ) // 组件中使用 import { connect } from 'react-redux' //use this.dispatch({ type: 'changeCount', payload: { count: 22 } }) const mapStateToProps = (state, props) => { return { name: state.demo.name } } export default connect( mapStateToProps )(Demo) 复制代码
mapStateToProps
mapStateToProps
mapDispatchToProps
mapDispatchToProps mapDispatchToProps
import { connect } from 'react-redux' import { bindActionCreators } from 'redux' // 页面中使用... this.props.changeName() const mapDispatchToProps = { changeName } = (dispatch, props) => { return bindActionCreators({ changeName: function() { return { type: types.UPDATE_NAME, payload: { name: '大大大' } } } }, dispatch) } export default connect( mapDispatchToProps )(App) 复制代码
模块化配置
下面的配置仅供参考。
安装
npm install redux react-redux redux-thunk --save npm install immutability-helper --save npm install babel-plugin-transform-decorators-legacy -D 复制代码
当state中存放的字段内存未发生改变时,视图并不会更新。所以借用到了 immutability-helper ,辅助更新 当然也可以替换掉json数组,这样便会触发视图的更新了。
src 下新建 store 文件,如下所示:
配置文件
types.js
文件
export const UPDATE_NAME = 'UPDATE_NAME' export const UPODATE_ARRAY = 'UPODATE_ARRAY' 复制代码
demoModule.js
文件
import * as types from '../types' import update from 'immutability-helper' const defaultState = { name: '默认值', jsonArray: [{ name: '数组默认值' }], array: [] } /** * demo reducer * */ export default function demo(state = defaultState, action = {}) { const { type, payload } = action const res = Object.assign({}, state) switch (type) { case types.UPDATE_NAME: res.name = payload.name break case types.UPODATE_ARRAY: res.jsonArray = update(state.jsonArray, { [0]: { $set: { name: payload.name } } }) break default: } return res } 复制代码
modeules
文件夹下的 index.js
(模块入口文件)
import { combineReducers } from 'redux' import demo from './demoModule' const Reducers = combineReducers({ demo }) export default Reducers 复制代码
combineReducers
: 用于合并 reducers
store
文件下的 index
( redux
总入口文件)
import { createStore, applyMiddleware, compose } from 'redux' import Modules from './modules' import thunk from 'redux-thunk' const store = createStore(Modules, compose( applyMiddleware(thunk), window.devToolsExtension && window.devToolsExtension() // 配置redux 开发工具 )); export default store 复制代码
-
Redux
默认只处理同步,异步任务需要redux-thunk
中间件 - 引入
applyMiddleware
来处理中间件 - 使用
compose
结合thunk
和window.devToolsExtension
修改src 下 index.js
(渲染根组件的入口文件)
import { Provider } from 'react-redux' import store from './store' ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root')) 复制代码
测试: demo.jsx
组件
import React, { Component } from 'react' import { connect } from 'react-redux' import * as types from './types' import axios from 'axios' import { Button } from 'antd' /** * @state store 中的state * @props 组件内接收的props 写了第二个参数props,那么当组件内props发生变化的时候,mapStateToProps也会被调用 * @return Object * */ const mapStateToProps = (state, props) => { return { name: state.demo.name, jsonArray: state.demo.jsonArray, array: state.demo.array, } } @connect(mapStateToProps) class App extends Component { constructor(props) { super(props) this.state = {} } handleClick = (type) => { switch (type) { case 1: // 常规调用 this.props.dispatch({ type: types.UPDATE_NAME, payload: { name: '同步调用redux' } }) break case 2: // 异步请求 this.props.dispatch( dispatch => { return axios.get('https://randomuser.me/api/').then( res => { dispatch({ type: types.UPDATE_NAME, payload: { name: res.data.results[0].name.title } }) } ) } ) break case 3: // 改变json数组,通过普通方式 this.props.dispatch({ type: types.UPODATE_ARRAY, payload: { name: '这是需要被渲染的 name' } }) break default: } } componentWillReceiveProps() { console.log('props change') } render() { const { name, jsonArray } = this.props return ( <div> name: {name} <br/> jsonArray[0]['name'] : {jsonArray[0]['name']}<br/> <Button onClick={e => this.handleClick(1)}>常规调用</Button> <Button onClick={e => this.handleClick(2)}>异步调用</Button> <Button onClick={e => this.handleClick(3)}>改变json数组</Button> </div> ) } } export default App 复制代码
上面用了装饰器模式来 connect , 配置一下 babel 就好了
"plugins": [ "transform-decorators-legacy" ] 复制代码
以上配置,仅供参考,网上有更多更好的,也求大家推荐一下更好地配置。这是一篇学习记录,学海无涯,希望自己加油...
参考
- 阮一峰 redux 入门教程
- 配置方案相关文件 store 文件夹
以上所述就是小编给大家介绍的《react-redux 学习以及模块化配置方案》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Android模块化改造以及模块化通信框架
- Laravel 模块化开发模块 – Caffienate
- 前端模块化架构设计与实现(二|模块接口设计)
- 模块化编程的实践者 disconver 更新了用户模块
- ASP.NET Core模块化前后端分离快速开发框架介绍之4、模块化实现思路
- JavaScript模块化
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
计算统计
Geof H.Givens、Jennifer A.Hoeting / 王兆军、刘民千、邹长亮、杨建峰 / 人民邮电出版社 / 2009-09-01 / 59.00元
随着计算机的快速发展, 数理统计中许多涉及大计算量的有效方法也得到了广泛应用与迅猛发展, 可以说, 计算统计已是统计中一个很重要的研究方向. 本书既包含一些经典的统计计算方法, 如求解非线性方程组的牛顿方法、传统的随机模拟方法等, 又全面地介绍了近些年来发展起来的某些新方法, 如模拟退火算法、基因算法、EM算法、MCMC方法、Bootstrap方法等, 并通过某些实例, 对这些方法的应用进行......一起来看看 《计算统计》 这本书的介绍吧!