react redux阮一峰怎么做登陆拦截

React和Redux的连接react-redux - 简书
React和Redux的连接react-redux
之前一直在探索React相关的东西,手上有个SPA项目,于是准备上Redux试试水。Redux本身和React并没有之间的关联,它是一个通用Javscript App模块,用做App State的管理。要在React的项目中使用Redux,比较好的方式是借助react-redux这个库来做连接,这里的意思是,并不是没有react-redux,这两个库就不弄一起用了,而是说react-redux提供了一些封装,一种更科学的代码组织方式,让我们更舒服地在React的代码中使用Redux。
之前仅通过Redux文档来了解react-redux,在一段时间的实践后准备翻一翻源代码,顺便做些相关的总结。我看的代码的npm版本为v4.0.0,也就是说使用的React版本是0.14.x。
react-redux提供两个关键模块:Provider和connect。
Provider这个模块是作为整个App的容器,在你原有的App Container的基础上再包上一层,它的工作很简单,就是接受Redux的store作为props,并将其声明为context的属性之一,子组件可以在声明了contextTypes之后可以方便的通过this.context.store访问到store。不过我们的组件通常不需要这么做,将store放在context里,是为了给下面的connect用的。
这个是Provider的使用示例:
// config app root
const history = createHistory()
const root = (
&Provider store={store} key="provider"&
&Router history={history} routes={routes} /&
&/Provider&
ReactDOM.render(
document.getElementById('root')
这个模块是算是真正意义上连接了Redux和React,正好它的名字也叫connect。
先考虑Redux是怎么运作的:首先store中维护了一个state,我们dispatch一个action,接下来reducer根据这个action更新state。
映射到我们的React应用中,store中维护的state就是我们的app state,一个React组件作为View层,做两件事:render和响应用户操作。于是connect就是将store中的必要数据作为props传递给React组件来render,并包装action creator用于在响应用户操作时dispatch一个action。
好了,详细看看connect这个模块做了什么。先从它的使用来说,它的API如下:
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
mapStateToProps是一个函数,返回值表示的是需要merge进props的state。默认值为() =& ({}),即什么都不传。
(state, props) =& ({
}) // 通常会省略第二个参数
mapDispatchToProps是可以是一个函数,返回值表示的是需要merge仅props的actionCreators,这里的actionCreator应该是已经被包装了dispatch了的,推荐使用redux的bindActionCreators函数。
(dispatch, props) =& ({ // 通常会省略第二个参数
...bindActionCreators({
...ResourceActions
}, dispatch)
更方便的是可以直接接受一个对象,此时connect函数内部会将其转变为函数,这个函数和上面那个例子是一模一样的。
mergeProps用于自定义merge流程,下面这个是默认流程,parentProps值的就是组件自身的props,可以发现如果组件的props上出现同名,会被覆盖。
(stateProps, dispatchProps, parentProps) =& ({
...parentProps,
...stateProps,
...dispatchProps
options共有两个开关:pure代表是否打开优化,详细内容下面会提,默认为true,withRef用来给包装在里面的组件一个ref,可以通过getWrappedInstance方法来获取这个ref,默认为false。
connect返回一个函数,它接受一个React组件的构造函数作为连接对象,最终返回连接好的组件构造函数。
然后几个问题:
React组件如何响应store的变化?
为什么connect选择性的merge一些props,而不是直接将整个state传入?
pure优化的是什么?
我们把connect返回的函数叫做Connector,它返回的是内部的一个叫Connect的组件,它在包装原有组件的基础上,还在内部监听了Redux的store的变化,为了让被它包装的组件可以响应store的变化:
trySubscribe() {
if (shouldSubscribe && !this.unsubscribe) {
this.unsubscribe = this.store.subscribe(::this.handleChange)
this.handleChange()
handleChange () {
this.setState({
storeState: this.store.getState()
但是通常,我们connect的是某个Container组件,它并不承载所有App state,然而我们的handler是响应所有state变化的,于是我们需要优化的是:当storeState变化的时候,仅在我们真正依赖那部分state变化时,才重新render相应的React组件,那么什么是我们真正依赖的部分?就是通过mapStateToProps和mapDispatchToProps得到的。
具体优化的方式就是在shouldComponentUpdate中做检查,如果只有在组件自身的props改变,或者mapStateToProps的结果改变,或者是mapDispatchToProps的结果改变时shouldComponentUpdate才会返回true,检查的方式是进行shallowEqual的比较。
所以对于某个reducer来说:
export default (state = {}, action) =& {
return { ...state } // 返回的是一个新的对象,可能会使组件reRender
// return state // 可能不会使得组件reRender
另外在connect的时候,要谨慎map真正需要的state或者actionCreators到props中,以避免不必要的性能损失。
最后,根据connect的API我们发现可以使用ES7 decorator功能来配合React ES6的写法:
state =& ({
user: state.user,
resource: state.resource
dispatch =& ({
...bindActionCreators({
loadResource: ResourceActions.load
}, dispatch)
export default class Main extends Component {
OK,结束了。尊重版权,未经授权不得转载
本文来自:江清清的技术专栏()
经过前期一段时间的开发,项目的页面基本已经模拟开发的差不多了。接下来的更多时间会放在逻辑功能实现上面,但是我们也知道,作为商城客户端里面的功能点会非常的多,而且功能还会有交叉。但是如果我们还是通过props以及state进行属性状态传值,随着项目持续迭代这种实现方式的弊端就会逐渐显现,而且基本没有什么扩展性。于是今天我们开始对项目做一下重构,主要添加一下Redux框架。
刚创建的React Native交流九群:,欢迎各位大牛,React Native技术爱好者加入交流!同时博客右侧欢迎微信扫描关注订阅号,移动技术干货,精彩文章技术推送!
本次重构项目相关环境如下:操作系统10.11.6,React Native版本:0.30.0
关于Redux的产生以及相关原理介绍,本文主要做简单的介绍,所以本文推荐以下几篇文章来加强大家的理解。在阅读本文的时候,也希望广大读者都可以把以下的几篇文章阅读理解一下。
(二)Flux介绍
因为Redux是基于Flux架构的,所以在学习Redux之前首先把Flux模式好好学习一番,首先来看一下官方的一张图:
Views可以在响应用户操作的时候产生新的Action,
Dispatcher是中心枢纽,管理着Flux应用中的所有数据流。它本质上是Store的回调注册。每个Store注册它自己并提供一个回调函数。当Dispatcher响应Action时,通过已注册的回调函数,将Action提供的数据负载发送给应用中的所有Store。
随着应用程序的增长,Dispatcher变得更加关键,因为它将管理Store之间的依赖,以特定的顺序调用注册的回调函数。Store可以声明等待其它Store完成更新后,再相应地更新自己??
Store包含应用程序的状态和逻辑。它们的角色某种程度上与传统MVC中的Model类似,但它们管理很多对象的状态,它们不是某个对象的实例,也不是Backbone集合。Store不只是简单地管理ORM风格的对象集合,它还为应用程序中的特定领域(Domain)管理应用状态。
(三)Redux介绍
Redux 是 JavaScript 状态容器,提供可预测化的状态管理。
可以让你构建一致化的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试。不仅于此,它还提供 超爽的开发体验。Redux 除了和 React 一起用外,还支持其它界面库。它体小精悍(只有2kB)且没有任何依赖。
在使用Redux的时候,需要记住:应用中所有的 state 都以一个对象树的形式储存在一个单一的 store 中。惟一改变 state 的办法是触发 action,一个描述发生什么的对象。为了描述 action 如何改变 state 树,你需要编写 reducers。
如果你以前使用 Flux,那么你只需要注意一个重要的区别。Redux 没有 Dispatcher 且不支持多个 store。相反,只有一个单一的 store 和一个根级的 reduce 函数(reducer)。随着应用不断变大,你应该把根级的 reducer 拆成多个小的 reducers,分别独立地操作 state 树的不同部分,而不是添加新的 stores。这就像一个 React 应用只有一个根级的组件,这个根组件又由很多小组件构成。
当然了,如果你需要使用Redux的时候,需要添加如下相关依赖组件或者工具,看一下package.json中的依赖信息:
特别说一下:redux-thunk库是为了实现异步的Action Creator来引入使用的。在Redux中有三个概念:Action,Store以及Reducer,下面我们从实际项目中的登录功能进行一步步重构。
(四)功能实现:
4.1.定义用户登录的ActionType数据(路径:./App/common/ActionType.js)
* 进行定义请求Action类型
'use strict';
export const PERFORM_LOGIN_ACTION = 'PERFORM_LOGIN_ACTION';
export const RECEIVE_LOGIN_ACTION = 'RECEIVE_LOGIN_ACTION';
4.2.实现具体的Action功能实现(路径:./App/actions/LoginAction.js)
* 用户登录Action操作
'use strict';
import * as types from '../common/ActionTypes';
import FetchHttpClient, { form,header } from 'fetch-http-client';
import {HOST,LOGIN_ACTION} from
'../common/Request';
import { toastShort } from '../utils/ToastUtil';
const client = new FetchHttpClient(HOST);
export function performLoginAction(username,password){
return dispatch =& {
dispatch(performLogin());
setTimeout(
client.addMiddleware(form());
client.addMiddleware(request =& {
request.options.headers['appkey'] = '8abea01567d5beaf90000';
client.post(LOGIN_ACTION, {
username: username,
password: password,
}).then(response =& {
return response.json();
}).then((result)=&{
dispatch(receiveLoginResult(result));
if(result.code === '0'){
//登录成功..
toastShort('登录成功...');
toastShort(result.msg);
}).catch((error) =& {
toastShort('网络发生错误,请重试!')
function performLogin() {
type: types.PERFORM_LOGIN_ACTION,
function receiveLoginResult(result){
type: types.RECEIVE_LOGIN_ACTION,
data: result
这个Action是异步实现的,这边说一下具体的行为方法:performLoginAction()
首先dispatch(performLogin())进行发出一个action,表示用户要进行登录操作了。
然后进行网络请求,正式执行登录操作,如果登录成功调用dispatch(receiveLoginResult(result))方法进行数据回调,如果失败直接弹出消息提醒即可。
上面完成了Action的定义,接下来来看一下Reducer:
4.3.具体Reducer实现(路径:./App/reducers/LoginReducers.js)
* 用户登录Reducers
'use strict';
import * as types from '../common/ActionTypes';
const initialState = {
loading : false,
export default function login(state = initialState, action){
switch (action.type) {
case types.PERFORM_LOGIN_ACTION:
return Object.assign({}, state, {
loading: true
case types.RECEIVE_LOGIN_ACTION:
return Object.assign({}, state, {
loading: false,
data: action.result
上面我们定义login()方法就是action行为的具体处理,该用于进行返回新的状态。当然了上面我介绍Redux的时候也强调过,在Redux中只允许只有一个store,所以当然业务功能比较多的时候,就需要进行分拆多个reducer进行组合合并,最终会有一个根reducer。
4.4.具体根Reducer实现(路径:./App/reducers/index.js)
'use strict';
import {combineReducers} from 'redux';
import login from './LoginReducers';
const rootReducer = combineReducers({
export default rootR
看上面代码,我们使用了combineReducers方法进行把所有的reducer进行组合。上面所有的reducer定义完成以后,下面就要开始定义Store了。
4.5.具体根Store实现(路径:./App/store/configure-store.js)
'use strict';
import {createStore, applyMiddleware} from 'redux';
import thunkMiddleware from 'redux-thunk';
import rootReducer from '../reducers/index';
const createStoreWithMiddleware = applyMiddleware(thunkMiddleware)(createStore);
export default function configureStore(initialState) {
const store = createStoreWithMiddleware(rootReducer, initialState);
上面是Store的一种写法,主要看两个方法:applyMiddleware和createStoreWithMiddleware。
4.6.最重要一步需要把数据流进行串联,使用Provider包裹整个程序入口并且传入store,具体实现代码如下:
import React, {Component} from 'react';
} from 'react-native';
import {Provider} from 'react-redux'
import configureStore from './store/configure-store'
import App from './app'
const store = configureStore();
class rootApp extends Component {
render() {
&Provider store={store}&
&/Provider&
export default rootA
4.7.最后一步骤:组件和状态connect(),我们来看一下具体登录页面Login.js中的写法:
function mapStateToProps(state) {
const { login } =
export default connect(mapStateToProps)(Login);
艰难的完成了以上这些步骤,感觉可以松口气了,但是我们还是来进行理一下这个流程:
用户进入登录界面,输入用户名和密码,然后点击用户登录。
发出action中的performLoginAction()方法,执行PERFORM_LOGIN_ACTION动作,此刻显示加载中loading界面
接着执行网络请求做用户登录,数据返回之后,执行RECEIVE_LOGIN_ACTION动作,然后进行改变状态,界面刷新,隐藏Loading界面,提醒登录登录的结果。
至此基本的功能实现代码全部完成了,接下来我们看一下运行的效果:
(五)最后总结
今天带着大家项目中加入了Redux框架,具体代码以及资源文章请详见项目登录页面功能:
刚创建的React Native交流九群:,欢迎各位大牛,React Native技术爱好者加入交流!同时博客右侧欢迎微信扫描关注订阅号,移动技术干货,精彩文章技术推送!
尊重原创,转载请注明:From Sky丶清() 侵权必究!
关注我的订阅号(codedev123),每天推送分享移动开发技术(Android/iOS),React Native技术文章,项目管理,程序猿日常点滴以及精品技术资讯文章(欢迎关注,精彩第一时间推送)。
关注我的微博,可以获得更多精彩内容
在线用户: 6今日访问: 9,854昨日访问: 21,540累计访问: 4,485,766react+redux项目如何对state进行初始化
最近在学习redux,对照着官网的示例学习,总有些不明白的地方,所以研究了一下redux源码,主要针对combineReducers、createStore进行分析
具体执行函数请参照,可将该文中的所有内容直接拷贝到中,通过打印出的内容了解执行逻辑。
redux的工作原理:
1. actions: action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作,一般情况下,我们通过Action创建函数来生成action,如function addTodo = (text) =& ({type: ADD_TODO, text});
2. reducers: 指明应用如何更新state。reducer就是一个纯函数,接收旧的state和action,返回新的state。通过combinReducers({reducer1, reducer2})将所有的reducer进行合并,返回一个combination(state, action)方法
3. store:通过createStore(reducer)创建store,该store对state进行了初始化,store有以下职责:
维持应用的
提供getState()方法获取
提供dispatch(action)方法更新
通过subscribe(listener)注册监听器;
通过subscribe(listener)返回的函数注销监听器。
1. reducers
每个传入combineReducers的 reducer都需要满足以下规则:
1. 所有未匹配到的action,必须把它接收到的第一个参数也就是那个state原封不动返回。
2. 永远不能返回undefined。当过早return时非常容易犯这个错误,为了避免错误扩散,遇到这种情况时 combineReducers会抛出异常。
3. 如果传入的state是undefined, 一定要返回对应reducer的初始state。根据上一条规则,初始state禁止使用undefined。使用ES6的默认参数值语法来设置初始state很容易,但你也可以手动检查第一个参数是否为undefined
在reducer里不能做如下操作:
1. 修改传入参数
2. 执行有副作用的操作,如API请求和路由跳转
3. 调用非纯函数,如Date.now()或Math.random()
//reducer1
const selectedReddit = (state = 'frontend', action) =& {
switch(action.type){
case 'SELECT_REDDIT':
return action.reddit
return state
//reducer2
const postsByReddit = (state = { }, action) =& {
switch (action.type) {
case INVALIDATE_REDDIT:
case RECEIVE_POSTS:
case REQUEST_POSTS:
//doSomething
return state
通过combineReducers可以将多个reducer合并到一起
2. combineReducers
function combineReducers(reducers){
var reducerKeys = Object.keys{reducers}
var finalReducers = {}
//将 key对应的对象不是function的reducer过滤掉
for(var i=0; i & reducerKeys. i++){
var key = reducerKeys[i]
if(NODE_ENV !== 'production'){
if(typeof reducers[key] === 'undefined'){
`No reducer provided for key "${key}"`
if(typeof reducers[key] === 'function'){
finalReducers[key] = reducers[key]
//typeof reducer === 'function'
var finalReducerKeys = Object.keys(finalReducers)
//combineReducers({})执行后,返回combination方法,执行该方法,返回一个合成state对象,state对象的结构由传入的多个reducer的key决定
// state对象的结构: {reducerName1: state1, reducerName2: state2}
return function combination(state = {}, action){
if (sanityError){
throw sanityError
if(NODE_ENV !== 'production'){
var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache)
if (warningMessage){
warning(warningMessage)
var hasChanged = false
var nextState = {}
for(var i = 0; i & finalReducerKeys. i++){
var key = finalReducerKeys[i]
var reducer = finalReducers[key]
var previousStateForKey = state[key]
var nextStateForKey = reducer(previousStateForKey, action)
if(typeof nextStateForKey === 'undefined'){
var errorMessage = getUndefinedStateErrorMessage(key, action)
throw new Error(errorMessage)
nextState[key] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
return hasChanged ? nextState : state
3. createStore
通过dispatch(action)执行reducer,通过switch判断该执行哪种操作。
通过getState()获取应用当前state
function createStore(reducer, preloadedState, enhancer){
if(typeof preloadedState === 'function' && typeof enhancer === 'undefined'){
enhancer = preloadedState
preloadedState = undefined
var currentReducer = reducer
var currentState = preloadedState
var currentListeners = []
var nextListeners = currentListeners
var isDispatching = false
function getState(){
return currentState
function dispatch(action){
isDispatching = true
console.log(`
&&&&&&&&&&&&执行combination start&&&&&&&&&&`);
currentState = currentReducer(currentState, action)
console.log(`
&&&&&&&&&&&&执行combination end, 当前state: '${JSON.stringify(currentState)}'
&&&&&&&&&&&&`);
isDispatching = false
var listeners = currentListeners = nextListeners
for(var i=0; i & listeners. i++){
var listener = listeners[i]
listener()
return action
console.log(` &&&&&&&&&&&&&&&&&&&&&初始化state,执行dispatch, start&&&&&&&&&&&&&&&&&&`);
dispatch({ type: ActionTypes.INIT })
console.log(` &&&&&&&&&&&&&&&&&&&&&初始化state,执行dispatch, end&&&&&&&&&&&&&&&&&&`);
看过本文的人也看了:
我要留言技术领域:
取消收藏确定要取消收藏吗?
删除图谱提示你保存在该图谱下的知识内容也会被删除,建议你先将内容移到其他图谱中。你确定要删除知识图谱及其内容吗?
删除节点提示无法删除该知识节点,因该节点下仍保存有相关知识内容!
删除节点提示你确定要删除该知识节点吗?

我要回帖

更多关于 reactredux阮一峰 的文章

 

随机推荐