React第七章 状态管理器Redux

173 阅读5分钟

第一节    深度学习Redux成员及其数据流

1、actions

.    actions其实是描述 操作的对象,我们调用dispatch时需要传入此对象

2、store

.    store是整个应用的数据存储仓库,负责我们全局管理端的状态数据存储

3、reducers

.    reducers接收action并更新store


4、注意:redux是一个单独的数据流框架,跟react没有直接的关系,我们也可以在JQ在其他的复杂项目里面使用redux进行数据管理,当我们不知道是否应该使用redux的时候,我们都是不需要的。因为只有我们很肯定redux能帮助我们管理好复杂项目数据流的时候它才能发挥它的威力,简单的项目我们使用state+props+context 或者 Hooks足够。

5、Redux数据流走向

6、其他数据状态管理对比学习

flux:

dva:

mobx:

vuex:

第二节    学习redux编写一个累加器程序

1、安装redux npm install rudex --save

2、编写使用redux的步骤(过程有点繁琐,别遗漏任何一个步骤)

2.1. 从redux 引入 createStore用来创建数据仓库store

createStore是一个函数,需要传入reducer作为参数,返回值是我们需要的store

2.2. 在使用页面引入数据仓库store

通过getState()方法可以获取到数据仓库里的状态数据state

通过dispatch(action)可以出发更改reducer函数

每次触发dispatch都会触发store.subscribe()方法,用来重新触发页面渲染

2.3代码展示,对应以上步骤

store.js

import { createStore } from 'redux';

// 编写我们的第一个reducer
const firstReducer = (state = 10, action) => {
    switch (action.type) {
        case 'add':
            return state + 1;
        case 'reduce':
            return state - 1;
        default:
            return state;
    }
}
// 创建数据仓库
const store = createStore(firstReducer);
export default store

FirstRedux.js

import React, { Component } from 'react';
import store from './store';
export default class FirstRedux extends Component {
    render() {
        return (
            <div>
                <h5>第2节、纯redux累加器</h5>
                {/* 通过我们的store 的 getState 可以获取到我们 state 数据 */}
                <p>{store.getState()}</p>
                <div>
                    {/* 通过我们的store 的 dispatch 可以改变数据 */}
                    <button onClick={()=>store.dispatch({type:'add'})}>加1</button>
                    <button onClick={()=>store.dispatch({type:'reduce'})}>减1</button>
                </div>
            </div>
        )
    }
}

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import ReduxDemo from './ReduxDemo';
import store from './redux-demo/store';
const render = ()=>{
    ReactDOM.render(<ReduxDemo></ReduxDemo>,document.getElementById('root'));
}
render();
store.subscribe(render);

第三节    react-redux使用

1、由于redux的写法太繁琐,还每次需要重新render,不太符合react

2、安装react-redux:npm install react-redux --save

3、React-redux 提供了2个 api 供我们使用

3.1 Provider    顶级组件,为我们(注入)提供数据功能

3.2 connect    高阶组件,为我们提供数据和方法(就是一个函数,传入一个组件,返回另一个新的组件)

4、如下是用react-redux 改造的累加器代码,只需要index.js 和 FirstRedux.js,store.js不变

5、改造中出现报错:检查react-dom、react、react-redux、redux版本后,重新安装一下,兼容问题消失

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import ReduxDemo from './ReduxDemo';
import store from './redux-demo/store';
import { Provider } from 'react-redux';

ReactDOM.render(
    <Provider store={store}>
        <ReduxDemo></ReduxDemo>
    </Provider>, document.getElementById('root')
);

FirstRedux.js

import React, { Component } from 'react';
import {connect} from 'react-redux';

// 返回数据方法,供我们的connect使用,他会将数据转换成props
const mapStateToProps = (state)=>{
    return {
        count:state
    }
}
// 返回dispatch方法的方法,供我们的connect使用,他会将dispatch转换成props
const mapDispatchToProps = (dispatch)=>{
    return {
        add:()=>dispatch({type:'add'}),
        reduce:()=>dispatch({type:'reduce'}),
    }
}
class FirstRedux extends Component {
    render() {
        return (
            <div>
                <h5>第3节、react-redux累加器</h5>
                <p>{this.props.count}</p>
                <div>
                    <button onClick={()=>this.props.add()}>加1</button>
                    <button onClick={()=>this.props.reduce()}>减1</button>
                </div>
            </div>
        )
    }
}
export default connect(mapStateToProps,mapDispatchToProps)(FirstRedux);

第四节    高阶组件装饰器模式简化封装代码

1、connect高阶组件使用装饰器会使我们的代码看起来更简洁易懂

2、代码如下:

FirstRedux.js

import React, { Component } from 'react';
import { connect } from 'react-redux';

@connect(
    state => ({ count: state }),
    // dispatch=>({
    //     add:()=>dispatch({type:'add'}),
    //     reduce:()=>dispatch({type:'reduce'})
    // })
    // 简写dispatch (因为dispath只支持同步写法)
    {
        add: () => ({ type: 'add' }),
        reduce: () => ({ type: 'reduce' })
    }
)
class FirstRedux extends Component {
    render() {
        return (
            <div>
                <h5>第3节、react-redux累加器</h5>
                <p>{this.props.count}</p>
                <div>
                    <button onClick={() => this.props.add()}>加1</button>
                    <button onClick={() => this.props.reduce()}>减1</button>
                </div>
            </div>
        )
    }
}
export default FirstRedux;

第五节    redux中间件:异步+日志

1、用于redux reducer默认只支持同步,实现异步任务或者延时任务时,我们就要借助中间件的支持了

2、学习两个中间件

2.1     redux-thunk 支持我们reducer在异步操作结束后自动执行

2.2    redux-logger 打印日志协助本地调试

2.3    安装:npm install redux-thunk redux-logger  --save

2.4    注意点:applyMiddleware(thunk,logger) 中间件的使用是有先后顺序的(先传入先试用),日志最好放在最后

3、使用例子 ****redux-logger

store.js

import { createStore, applyMiddleware } from 'redux';
import logger from 'redux-logger'
// 编写我们的第一个reducer
const firstReducer = (state = 10, action) => {
    switch (action.type) {
        case 'add':
            return state + 1;
        case 'reduce':
            return state - 1;
        default:
            return state;
    }
}
// 创建数据仓库
const store = createStore(firstReducer,applyMiddleware(logger));
export default store

页面效果

4、使用例子 ****redux-thunk

FirstRedux.js

import React, { Component } from 'react';
import { connect } from 'react-redux';

@connect(
    state => ({ count: state }),
    {
        add: () => ({ type: 'add' }),
        reduce: () => ({ type: 'reduce' }),
        asyncAdd:() => dispatch=>{
            setTimeout(()=>{
                dispatch({type: 'add'})
            },2000)
        }
    }
)
class FirstRedux extends Component {
    render() {
        return (
            <div>
                <p>{this.props.count}</p>
                <div>
                    <button onClick={() => this.props.add()}>加1</button>
                    <button onClick={() => this.props.reduce()}>减1</button>
                    <button onClick={() => this.props.asyncAdd()}>延时加1</button>
                </div>
            </div>
        )
    }
}
export default FirstRedux;

注意点:不使用中间件异步报错

store.js 使用中间件,进行异步的reducer,更新store数据。

import { createStore, applyMiddleware } from 'redux';
import logger from 'redux-logger';
import thunk from 'redux-thunk';

// 编写我们的第一个reducer
const firstReducer = (state = 10, action) => {
    switch (action.type) {
        case 'add':
            return state + 1;
        case 'reduce':
            return state - 1;
        default:
            return state;
    }
}
// 创建数据仓库
const store = createStore(firstReducer,applyMiddleware(thunk,logger));
export default store

第六节    抽离reducer和action统一管理

1、不在组件内定义reducer的action,集中管理

sotre.js 数据仓库 action定义。

// 编写我们的第一个reducer
const firstReducer = (state = 10, action) => {
    switch (action.type) {
        case 'add':
            return state + 1;
        case 'reduce':
            return state - 1;
        default:
            return state;
    }
}
const add = () => ({ type: 'add' });
const reduce = () => ({ type: 'reduce' });
const asyncAdd = () => dispatch => {
    setTimeout(() => {
        dispatch({ type: 'add' })
    }, 2000)
}
export {firstReducer,add,reduce,asyncAdd,}

index.js 入口主文件 创建数据仓库

import React from 'react'
import ReactDOM from 'react-dom'
import ReduxDemo from './ReduxDemo';
import { Provider } from 'react-redux';
import { firstReducer } from './redux-demo/store';
import { createStore, applyMiddleware } from 'redux';
import logger from 'redux-logger';
import thunk from 'redux-thunk';
// 创建数据仓库
const store = createStore(firstReducer, applyMiddleware(thunk, logger));
ReactDOM.render(
    <Provider store={store}>
        <ReduxDemo></ReduxDemo>
    </Provider>, document.getElementById('root')
);

FirstRedux.js 实际使用,绑定到了props上的action。

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { add, reduce, asyncAdd } from './store';

@connect(
    state => ({ count: state }),
    { add, reduce, asyncAdd }
)
class FirstRedux extends Component {
    render() {
        return (
            <div>
                <h5>第3节、react-redux累加器</h5>
                <p>{this.props.count}</p>
                <div>
                    <button onClick={() => this.props.add()}>加1</button>
                    <button onClick={() => this.props.reduce()}>减1</button>
                    <button onClick={() => this.props.asyncAdd()}>延时加1</button>
                </div>
            </div>
        )
    }
}
export default FirstRedux;