Redux复习总结

276 阅读4分钟

Redux

mobx 也不错

和vuex去区别

无异步操作,只能dispatch

依赖

npm install redux -S

1.简单上手

1.store.js

import { createStore } from 'redux'

//必须是一个函数(初始化状态)
const countReducer = (state=0,action)=>{
    switch(action.type){
        case 'add':
            return state+=1
            break;
        case 'minus':
             return state-=1
            break;
        default:
            return state;
    }
}

const store = createStore(countReducer);

export default store;

2.ReduxTest.js

import React from 'react'
import store from  './store'

export default function ReduxTest(){
    return (
        <div>
            <p onClick={()=>store.dispatch({type:'minus'})}>减</p>
            <p>{store.getState()}</p>
            <p onClick={()=>store.dispatch({type:'add'})}>加</p>
        </div>
    )
}

3.订阅状态更新 index.js

import store from  './store'
ReactDOM.render(<App />, document.getElementById('root'));
store.subscribe(()=>{
    ReactDOM.render(<App />, document.getElementById('root'));
})

2.react-redux

1.安装

npm install react-redux -S

2.Provider

不在需要订阅状态,但需要包括顶级组件 APP.js

import { Provider } from 'react-redux'
import store from './store'

function App() {
  return (
    <div className="App">
        <Provider store={ store }>
            <header className="App-header">
                <h1>hello word</h1>
                <Index name='哈哈' />
            </header>
        </Provider>
    </div>
  );
}
//实际内部为上下文

3.ReduxTest.js

import React from 'react'
// import store from  './store'
import { connect } from 'react-redux'

const mapStateToProps = state => ({num: state})

const mapDispatchToProps = {
    add:()=>({type:'add'}),
    minus:()=>({type:'minus'})
}


function ReduxTest({num,add,minus}){
    return (
        <div>
            <p onClick={minus}></p>
            <p>{num}</p>
            <p onClick={add}></p>
        </div>
    )
}

export default connect(
    mapStateToProps,
    mapDispatchToProps
    )(ReduxTest);


4.ReduxTest.js 装饰器写法

import React from 'react'
// import store from  './store'
import { connect } from 'react-redux'

const mapStateToProps = state => ({num: state})

const mapDispatchToProps = {
    add:()=>({type:'add'}),
    minus:()=>({type:'minus'})
}

@connect(mapStateToProps,mapDispatchToProps)
class ReduxTest extends Component{
    render(){
        const {minus , num, add } = this.props;
        return (
            <div>
                <p onClick={minus}></p>
                <p>{num}</p>
                <p onClick={add}></p>
            </div>
        )
    }
}

export default ReduxTest;

3.redux-thunk(异步操作)

1.安装

npm install redux-thunk -S
npm install redux-logger -S

2.store.js

import { createStore, applyMiddleware } from 'redux'

import logger from 'redux-logger'
import thunk from 'redux-thunk'
//必须是一个函数(初始化状态)
const countReducer = (state=0,action)=>{
    switch(action.type){
        case 'add':
            return state+=1
            break;
        case 'minus':
             return state-=1
            break;
        default:
            return state;
    }
}

//注意 applyMiddleware 顺序 先logger 日志记录,再thunk 异步
const store = createStore(countReducer, applyMiddleware(logger,thunk));

export default store;

3.ReduxTest.js

import React from 'react'
// import store from  './store'
import { connect } from 'react-redux'

const mapStateToProps = state => ({num: state})

const mapDispatchToProps = {
    add:()=>({type:'add'}), //返回的是一个对象
    minus:()=>({type:'minus'}),
    asyncAdd: () => dispatch =>{ //返回的是一个函数
        setTimeout(()=>{
            dispatch({type: 'add'})
        },1000)
    }
}

@connect(mapStateToProps,mapDispatchToProps)
class ReduxTest extends Component{
    render(){
        const {minus , num, add, asyncAdd } = this.props;
        return (
            <div>
                <p onClick={minus}></p>
                <p>{num}</p>
                <p onClick={add}></p>
                <p onClick={asyncAdd}>异步</p>
            </div>
        )
    }
}

export default ReduxTest;

4.重构以上代码

1.store/index.js

import { createStore, applyMiddleware } from 'redux'

import logger from 'redux-logger'
import thunk from 'redux-thunk'

import { countReducer } from './countRedux'  //导入状态

//注意 applyMiddleware 顺序 先logger 日志记录,再thunk 异步
const store = createStore(countReducer, applyMiddleware(logger,thunk));

export default store;

  1. store/countRedux.js
//必须是一个函数(初始化状态)
export const countReducer = (state=0,action)=>{
    switch(action.type){
        case 'add':
            return state+=1
            break;
        case 'minus':
             return state-=1
            break;
        default:
            return state;
    }
}

//action creator
export const add = () =>({type:'add'}); //返回的是一个对象

export const minus = ()=>({type:'minus'})

export const asyncAdd = () => dispatch =>{ //返回的是一个函数
        setTimeout(()=>{
            dispatch({type: 'add'})
        },1000)
    }
}

3.ReduxTest.js

import React from 'react'
// import store from  './store'
import { connect } from 'react-redux'
import { add,minus,asyncAdd} from './store/countRedux'

const mapStateToProps = state => ({num: state})

const mapDispatchToProps = {add,minus,asyncAdd}

@connect(mapStateToProps,mapDispatchToProps)
class ReduxTest extends Component{
    render(){
        const {minus , num, add, asyncAdd } = this.props;
        return (
            <div>
                <p onClick={minus}></p>
                <p>{num}</p>
                <p onClick={add}></p>
                <p onClick={asyncAdd}>异步</p>
            </div>
        )
    }
}

export default ReduxTest;

5.模块化

1.store/index.js

import { createStore, applyMiddleware, combineReducers } from 'redux'

import logger from 'redux-logger'
import thunk from 'redux-thunk'

import { countReducer } from './countRedux'  //导入状态

//注意 applyMiddleware 顺序 先logger 日志记录,再thunk 异步
const store = createStore( combineReducers({
        count:countReducer
}), applyMiddleware(logger,thunk));

export default store;

2.ReduxTest.js

import React from 'react'
// import store from  './store'
import { connect } from 'react-redux'
import { add,minus,asyncAdd} from './store/countRedux'

const mapStateToProps = state => ({num: state.count})

const mapDispatchToProps = {add,minus,asyncAdd}

@connect(mapStateToProps,mapDispatchToProps)
class ReduxTest extends Component{
    render(){
        const {minus , num, add, asyncAdd } = this.props;
        return (
            <div>
                <p onClick={minus}></p>
                <p>{num}</p>
                <p onClick={add}></p>
                <p onClick={asyncAdd}>异步</p>
            </div>
        )
    }
}

6.redux-saga

redux-saga 和redex-thunk 都是异步数据处理

1.安装

npm install redux-saga -S

2.store/saga.js

/**
* call   //调用异步函数
* put    //执行完异步后 通知更新状态
* takeEvery   //全局鉴定 action
*/
import { call, put, takeEvery } from 'redux-saga/effects';


//模拟用户登录
const UserService = {
    login(uname){
        return new Promise((resolve,reject) => {
            setTimeout(() => {
                if(uname == 'abc'){
                    resolve({ id: 1 , name: '小明'})
                } else {
                    reject('用户名或密码错误')
                }
            },1000)
        })
    }
}

//带* 为生成器函数 
function* login(action){
    tyr{
        yield put({ type : 'requestLigin'});//提交action
        const result = tield call(UserService.login,action.name);
        yield put({ type: 'loginSuccess', result })
    }catch(message) {
        yield put({ type: 'loginFailuer', message })
    }
}

function* mySaga(){
    yield takeEvery('login', login)
}
export default mySaga;

3.注册 store/index.js

import createSagaMiddleware from 'redux-saga'
import mySaga from './store/saga.js'

//1.创建中间件
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
    combineReducers({ user }),
    applyMiddleware(logger, sagaMiddleware)
)

//2.中间件运行
sagaMiddleware.run(mySaga);

export default store;

4.user.redux.js

export const user = (
    state = {
        isLogin: false,
        loading: false,
        error: ''
    },
    action
) => {
    switch (active.type){
        case: 'requestLigin'
            return { isLogin: false, loading: true, error: ''}
        break;
        case: 'loginSuccess'
            return { isLogin: true, loading: false, error: ''}
        break;
        case: 'loginFailuer'
            return { isLogin: false, loading: false, error: action.message }
        break;

    }
}

expore function login(uname){
    return { type: 'login', uname}
}

7.生成器函数

function* g(a){
    yield a;
    yield 'b';
    yield 'c';
    return 'ending'
}

//第一次传参,要传给构造函数
var gen = g('a')
console.log(gen.next()) //{ value: 'a', done: false }
console.log(gen.next()) //{ value: 'b', done: false }
console.log(gen.next()) //{ value: 'c', done: false }
console.log(gen.next()) //{ value: 'd', done: true }


function next(){
    let { value,done } = gen.next()
    if(!done){
        next()
    }
}

next()

2.传至 计算

function r(num){
    const r1 = yield compute(num)
    yield compute(r1)
}

function compute(num){
    return new Promise(resolve => {
        setTimeout(()=>{
            const ret = num*num
            resolve(ret)
        },1000)
    } )
}

let it = r(2)
// it.next().value.then(num => it.next(num));

function next(data){
    let { value,done } = it.next(data);
    if(!done){
        value.then(num => {
            next(num);
        })
    }
}

next()