redux的使用

前言

想要在react里面使用状态管理,redux就是最好的选择。更加详细的介绍:http://cn.redux.js.org/docs/basics/Reducers.html

Action

Action 本质上是 JavaScript 普通对象。我们约定,action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作。多数情况下,type 会被定义成字符串常量。当应用规模越来越大时,建议使用单独的模块或文件来存放 action。

下面return的对象就是action,而return该对象的函数我们叫Action创建函数

// action

export const INCREMENT = "counter/INCREMENT"
export const DECREMENT ="counter/DECREMENT"
export const RESET ="counter/RESET"
export function increment(){
    return {
        type:INCREMENT
    }
}
export function decrement() {
    return {
        type:DECREMENT
    }
}
export function reset(){
    return {
        type:RESET
    }
}

当然,action还可以返回一个函数,但是这里我们需要引入中间件react-thunk,在下面的异步请求action会介绍。

Reducer

reducer,就是通过对应不同的action.type,做不同的处理,return不同的state,改变state。例子:

//这是对应action里面的counter的reducers
import { INCREMENT, DECREMENT, RESET } from '../actions/counter';

/*
*初始化state
*/
const iniState={
    count:0
};
/*
*reducer
*/
export default function reducer(state=iniState,action) {
    switch (action.type) {
        case INCREMENT:
        console.log('count',state.count)
            return {
                count:state.count+1
            };
        case DECREMENT:
            return{
                count: state.count - 1 
            };
        case RESET:
            return{
                count:0
            };
        default:
            return state
    }
}

这里也可以定义多个reducer,不过要借助combineReducers把多个reducer联合起来,再export出去。如下:

import { BEFORESEND, SUCCESS, FAIL} from '../actions/asyn'
//实现异步网络请求的reducer
import {combineReducers} from 'redux'
const initState={
    status:'',
    result:''
}

function beforeSend(state=initState,action){
    switch (action.type) {
        case BEFORESEND:
        console.log('请求发起');
            return Object.assign({},state,{
                status:'状态-请求发起前'
            })
            break;
    
        default:
            return state
            break;
    }
}

function fetchResult(state=initState,action){
    switch (action.type) {
        case SUCCESS:
        console.log('请求成功');
            return Object.assign({},state,{
                status:'状态-请求成功',
                result:action.result
            })
            break;
        case FAIL:
        console.log('请求失败');
            return Object.assign({},state,{
                status:'状态-请求失败',
                result:action.result
            })
            break
        default:
            return state;
            break;
    }
}

const asyn=combineReducers({
    beforeSend,
    fetchResult
})

export default asyn;

Store

在前面的章节中,我们学会了使用 action 来描述“发生了什么”,和使用 reducers 来根据 action 更新 state 的用法。

Store 就是把它们联系到一起的对象。Store 有以下职责:

再次强调一下 Redux 应用只有一个单一的 store。当需要拆分数据处理逻辑时,你应该使用 reducer 组合而不是创建多个 store。

扫描二维码关注公众号,回复: 2866451 查看本文章

根据已有的 reducer 来创建 store 是非常容易的。在前面,我们使用 combineReducers() 将多个 reducer 合并成为一个。

现在,我们在store中也要这样使用,我们将所有reducer导入,再把导入的所有reducer用combineReducers()并,传递给 createStore()

/**
 * store是用于连接action和reducers,store的职责如下:
 * 1、维持应用的 state;
 * 2、提供 getState() 方法获取 state;
 * 3、提供 dispatch(action) 触发reducers方法更新 state;
 * 4、通过subscribe(listener) 注册监听器;
 * 5、通过 subscribe(listener) 返回的函数注销监听器。
 */
import thunkMiddleware from 'redux-thunk'; //引入中间件,让action不仅返回一个对象,还可以返回函数,可以dispatch函数,用作请求异步。
import { createLogger } from 'redux-logger';
import { createStore, applyMiddleware} from 'redux';
import combineReducers from './reducers.js';
const loggerMiddleware = createLogger()

 let store = createStore(
     combineReducers
    );

 export default store;

此时,我们使用dispatch就可以发起action:

import {increment,decrement,reset} from './actions/counter';
import {add,des} from './actions/userInfo'
import store from './store';

//打印初始状态
console.log(store.getState());

/**
 * 每次state更新时,打印日志
 *  subscribe() 返回一个函数用来注销监听器,执行unsubscribe(),就是注销监听器
 */
let unsubscribe=store.subscribe(()=>
        console.log(store.getState())
)

store.dispatch(add());
store.dispatch(des());

unsubscribe();

此时,我们在控制台就能看到每次dispatch改变state的结果。

React和Redux搭配

那么,如果想在react组件里面使用redux,该如何使用呢?当然,我们可以import store到组件了,直接使用store.dispatch,但是,我们一般不会这样做。我们一般会使用Provider和connect。

Provider

<Provider store>

<Provider store> 使组件层级中的 connect() 方法都能够获得 Redux store。正常情况下,你的根组件应该嵌套在 <Provider> 中才能使用 connect() 方法。

provider可以把store传递给所有使用了connect的子组件。

普通例子:

ReactDOM.render(
  <Provider store={store}>
    <MyRootComponent />
  </Provider>,
  rootEl
)

在路由中使用:

const getRouter = () => (
<Provider store = {store} >
    <Router>
        <div>
            <ul>
                <li>
                    <Link to="/">首页</Link>
                </li>
                <li>
                    <Link to="/page1">Page1</Link>
                </li>
            </ul>
            <Switch>
                <Route exact path="/" component={Home}/>
                <Route path="/page1" component={Page1}/>
            </Switch>
        </div>
    </Router>
</ Provider>
);

connect

connect,用于组件和redux连接起来。其实就是相当于高阶组件,通过connet,把现有的组件,添加自己的逻辑,使得组件可以通过props使用redux的state和dispatch方法。

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])


参数

  • [mapStateToProps(state, [ownProps]): stateProps] (Function): 如果定义该参数,组件将会监听 Redux store 的变化。任何时候,只要 Redux store 发生改变,mapStateToProps 函数就会被调用。该回调函数必须返回一个纯对象,这个对象会与组件的 props 合并。如果你省略了这个参数,你的组件将不会监听 Redux store。如果指定了该回调函数中的第二个参数 ownProps,则该参数的值为传递到组件的 props,而且只要组件接收到新的 props,mapStateToProps 也会被调用(例如,当 props 接收到来自父组件一个小小的改动,那么你所使用的 ownProps 参数,mapStateToProps 都会被重新计算)。

    注意:在高级章节中,你需要更好地去控制渲染的性能,所用到的 mapStateToProps() 会返回一个函数。在这种情况下,那个函数将被作为 mapStateToProps() 在独有的组件实例中调用。这样就允许你在每一个实例中去记录。你可以参考 #279 去测试和了解其中的详细内容。但在绝大多数的应用中不会用到。

  • [mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function): 如果传递的是一个对象,那么每个定义在该对象的函数都将被当作 Redux action creator,对象所定义的方法名将作为属性名;每个方法将返回一个新的函数,函数中dispatch方法会将action creator的返回值作为参数执行。这些属性会被合并到组件的 props 中。

    [mergeProps(stateProps, dispatchProps, ownProps): props] (Function): 如果指定了这个参数,        mapStateToProps() 与 mapDispatchToProps() 的执行结果和组件自身的 props 将传入到这个回调函数中。该回调函数返回的对象将作为 props 传递到被包装的组件中。你也许可以用这个回调函数,根据组件的 props 来筛选部分的 state 数据,或者把 props 中的某个特定变量与 action creator 绑定在一起。如果你省略这个参数,默认情况下返回 Object.assign({}, ownProps, stateProps, dispatchProps) 的结果。

    

            [options(Object) 如果指定这个参数,可以定制 connector 的行为。

  • [pure = true(Boolean): 如果为 true,connector 将执行 shouldComponentUpdate 并且浅对比 mergeProps 的结果,避免不必要的更新,前提是当前组件是一个“纯”组件,它不依赖于任何的输入或 state 而只依赖于 props 和 Redux store 的 state。默认值为 true
  • [withRef = false(Boolean): 如果为 true,connector 会保存一个对被被包含的组件实例的引用,该引用通过 getWrappedInstance() 方法获得。默认值为 false

简单的使用实例:

import React, {Component} from 'react';
import { connect } from 'react-redux';
import {increment} from '../../redux/actions/counter'

const mapStateToProps=(state)=>{
    return {
        counter:state.counter.count
    }
}
const mapDispatchToProps=(dispatch,ownProps) =>{
    return {
        increment:()=>dispatch(increment())
    }
}
class Home extends Component {
    constructor(props){
        super(props);
        this.state={
            count:0
        }
        }
        render() {
            return (
                <div>
                    this is home.<br/>
                    当前计数:{this.props.counter}<br/>
                    <button onClick={()=>this.props.increment()}>自增</button>
                </div>
            )
        }
}

export default connect(mapStateToProps,mapDispatchToProps)(Home)


异步Action的使用

如果,我们需要发起一个网络请求,结果需要改变redux里面的状态。我们可以在请求前调用dispatch,请求结束再dispatch另外一个action。这里,我们可以通过中间件的使用,只需要使用一个dispatch,即可完成请求前后的dispatch。

react-thunk

使用react-thunk中间件,可以帮助我们把action创建函数只能返回对象,改造成可以返回一个function。

store.js

import thunkMiddleware from 'redux-thunk'; //引入中间件,让action不仅返回一个对象,还可以返回函数,可以dispatch函数,用作请求异步。
import { createLogger } from 'redux-logger';
import { createStore, applyMiddleware} from 'redux';
import combineReducers from './reducers.js';
const loggerMiddleware = createLogger()

 let store = createStore(
     combineReducers,
     applyMiddleware(
         thunkMiddleware, // 允许我们 dispatch() 函数
         loggerMiddleware // 一个很便捷的 middleware,用来打印 action 日志
     )
    );

 export default store;

reducer.js

export const BEFORESEND='asyn/beforeSend';
export const SUCCESS = 'asyn/success';
export const FAIL = 'asyn/fail';

export function beforeSend() {
    return{
        type: BEFORESEND
    }
}

export function success(result) {
    return{
        type: SUCCESS,
        result
    }
}

export function fail(result) {
    return {
        type: FAIL,
        result
    }
}

//thunk action函数
//用法和普通action一样,只是return不是一个对象,是函数
export function fetchPosts() {
    //使用了thunk中间件,知道该如何 处理此函数
    /**
     * 把dispatch方法通过参数形式传递给函数
     * 该函数内部就能自己dispatch action
     */
    return function (dispatch) {
        dispatch(beforeSend());     //这里dispatch一个方法,代表请求发起前
        
        /**
         * 这里使用Promise+settimeout模拟网络请求
         */
        new Promise((resolve,reject)=>{
            setTimeout(() => {
                reject('结果-异步请求失败')
                resolve('结果-异步请求成功');
            }, 300);
        }).then((data)=>{
            /**
             * 使用请求结果来更新应用对应的state,
             * 可以使用多个dispatch
             */
            dispatch(success(data));

        }).catch((data)=>{
            dispatch(fail(data));
        })
    }
}

直接使用dispatch,即可以发起一个异步action

import {fetchPosts} from '../../redux/actions/asyn';
const mapDispatchToProps=(dispatch,ownProps) =>{
    return {
        fetch:()=>dispatch(fetchPosts())
    }
}


参考:http://cn.redux.js.org/docs/react-redux/api.html


猜你喜欢

转载自blog.csdn.net/chiuwingyan/article/details/80682315
今日推荐