zoukankan      html  css  js  c++  java
  • redux、react-redux、redux-thunk、redux-saga使用及dva对比

    一、redux使用

      Redux的核心概念其实很简单:将需要修改的state都存入到store里,发起一个action用来描述发生了什么,用reducers描述action如何改变state tree 。创建store的时候需要传入reducer,真正能改变store中数据的是store.dispatch API。

    1、src下新建store文件夹,新建index.js作为store的输出文件

    2、store文件夹下新建index.js文件

    3、新建reducer.js ,actionTypes.js文件

    4、组件引入store

    import React, { Component } from 'react';
    import { Input ,Button,List } from 'antd';
    import store from './store';
    import {CHANGE_INPUT_VALUE,ADD_TODO_ITEM,DELETE_TODO_ITEM} from  './store/actionTypes'
    
    class TodoList extends Component {
        constructor(props) {
            super(props);
            this.state = store.getState();
            this.handleStoreChange = this.handleStoreChange.bind(this);
            this.handleBtnClick = this.handleBtnClick.bind(this);
            this.handleInputChange = this.handleInputChange.bind(this);
            store.subscribe(this.handleStoreChange)
        }
        
        handleInputChange(e) {
            const action = {
                type: CHANGE_INPUT_VALUE,
                value: e.target.value
            }
            store.dispatch(action)
        }
    
        handleBtnClick() {
            const action = {
                type: ADD_TODO_ITEM
            }
            store.dispatch(action)
        }
        
        render() {
            return (
                <div style={{marginTop:'20px',marginLeft:'15px'}}>
                    <div>
                        <Input 
                            value={this.state.inputValue} 
                            placeholder="input" 
                            style={{'300px'}}
                            onChange={this.handleInputChange}
                        />
                        <Button onClick={this.handleBtnClick} type="primary">Primary</Button>
                    </div>
                    <List
                        style={{marginTop:'15px','300px'}}
                        bordered
                        dataSource={this.state.list}
                        renderItem={(item,index) => <List.Item onClick={this.handleItemDelete.bind(this,index)}>{item}</List.Item>}
                        />
                </div>
            )
        }
    
        handleStoreChange() {
            this.setState(store.getState())
        }
        handleItemDelete(index) {
            const action = {
                type: DELETE_TODO_ITEM,
                index
            }
            store.dispatch(action)
        }
    }
    
    export default TodoList;

    5、使用redux-devtool

    import { createStore } from 'redux';
    import reducer from './reducer'
    
    
    const store = createStore(
        reducer,
        window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
    );
    
    export default store;

     6、actionTypes.js代码如下

    export const  CHANGE_INPUT_VALUE = 'change_input_value';
    export const  ADD_TODO_ITEM = 'add_todo_item';
    export const  DELETE_TODO_ITEM = 'delete_todo_item';

    7、reducer.js代码如下

    import {CHANGE_INPUT_VALUE,ADD_TODO_ITEM,DELETE_TODO_ITEM} from  './actionTypes'
    const defaultState = {
        inputValue:'aaa',
        list:['1','2']
    }
    
    export default (state = defaultState,action) => {
        if(action.type === CHANGE_INPUT_VALUE) {
            const newState = JSON.parse(JSON.stringify(state));
            newState.inputValue = action.value;
            return newState;
        }
        if(action.type === ADD_TODO_ITEM) {
            const newState = JSON.parse(JSON.stringify(state));
            newState.list.push(newState.inputValue);
            newState.inputValue = '';
            return newState;
        }
        if(action.type === DELETE_TODO_ITEM) {
            const newState = JSON.parse(JSON.stringify(state));
            newState.list.splice(action.index,1);
            return newState;
        }
        return state;
    }

    8、优化:使用actionCreactor.js来统一管理action

    二、引入react-redux

    1.在index.js里引入react-redux及store

    import React from 'react';
    import ReactDOM from 'react-dom';
    import 'antd/dist/antd.css';
    import './index.css';
    import App from './TodoList';
    import * as serviceWorker from './serviceWorker';
    import store from './store'
    import { Provider } from 'react-redux';
    
    const ProviderApp = (
        <Provider store={store}>
            <App></App>
        </Provider>
    )
    
    ReactDOM.render(ProviderApp, document.getElementById('root'));
    serviceWorker.unregister();

    2.在组件里做connect

    import React, { Component } from 'react';
    import { Input ,Button,List } from 'antd';
    import {CHANGE_INPUT_VALUE,ADD_TODO_ITEM} from  './store/actionTypes'
    import {connect} from 'react-redux';
    
    
    class TodoList extends Component {
        render() {
            const {handleInputChange,handleBtnClick} = this.props
            return (
                <div style={{marginTop:'20px',marginLeft:'15px'}}>
                    <div>
                        <Input 
                            value={this.props.inputValue} 
                            placeholder="input" 
                            style={{'300px'}}
                            onChange={handleInputChange}
                        />
                        <Button onClick={handleBtnClick} type="primary">Primary</Button>
                    </div>
                    <List
                        style={{marginTop:'15px','300px'}}
                        bordered
                        dataSource={this.props.list}
                        renderItem={(item,index) => <List.Item>{item}</List.Item>}
                        />
                </div>
            )
        }
        
    }
    const mapStateToProps = (state) => {
        return {
            inputValue: state.inputValue,
            list : state.list
        }    
    }
    
    const mapDispatchToProps = (dispatch) => {
        return {
            handleInputChange(e) {
                const action = {
                    type: CHANGE_INPUT_VALUE,
                    value: e.target.value
                }
                dispatch(action)
            },
            handleBtnClick() {
                const action = {
                    type: ADD_TODO_ITEM
                }
                dispatch(action)
            },
    
        }
    }
    
    export default connect(mapStateToProps,mapDispatchToProps)(TodoList);

    三、redux-thunk使用

    1.中间件的概念

      dispatch一个action之后,到达reducer之前,进行一些额外的操作,就需要用到middleware。你可以利用 Redux middleware 来进行日志记录、创建崩溃报告、调用异步接口或者路由等等。
      换言之,中间件都是对store.dispatch()的增强。redux-thunk就是用来异步操作,比如接口请求等。

    2.引入redux-thunk

    import { applyMiddleware, createStore } from 'redux';
    import thunk from 'redux-thunk';
     const store = createStore(
      reducers, 
      applyMiddleware(thunk)
    );
    

    3.这样就可以再actionCreactor中创建一个带异步函数的方法了

    export const getTodoList = () => {
        return () => {
            axios.get('./list').then((res)=>{
                const data = res.data;
                const action  = initListAction(data);
                StorageEvent.dispatch(action);
            })
        }
    }

    四、redux-saga使用

      redux-saga是一个用于管理redux应用异步操作的中间件,redux-saga通过创建sagas将所有异步操作逻辑收集在一个地方集中处理,可以用来代替redux-thunk中间件。

    1.在store.js里引入redux-saga

    import { createStore, applyMiddleware } from 'redux'
    import createSagaMiddleware from 'redux-saga'
    
    import reducer from './reducers'
    import mySaga from './sagas'
    
    // create the saga middleware
    const sagaMiddleware = createSagaMiddleware()
    // mount it on the Store
    const store = createStore(
      reducer,
      applyMiddleware(sagaMiddleware)
    )
    
    // then run the saga
    sagaMiddleware.run(mySaga);
    export default store;

    2.新建 saga.js

    import { call, put, takeEvery, takeLatest } from 'redux-saga/effects'
    import Api from '...'
    
    // worker Saga: will be fired on USER_FETCH_REQUESTED actions
    function* fetchUser(action) {
       try {
          const user = yield call(Api.fetchUser, action.payload.userId);
          yield put({type: "USER_FETCH_SUCCEEDED", user: user});
       } catch (e) {
          yield put({type: "USER_FETCH_FAILED", message: e.message});
       }
    }
    function* mySaga() {
      yield takeEvery("USER_FETCH_REQUESTED", fetchUser);
    }
    
    export default mySaga;

     五、dva对比

    dva使用可以参考这个博客:https://www.cnblogs.com/superSmile/p/9972344.html

  • 相关阅读:
    23种设计模式之原子模式
    23种设计模式之外观模式(门面模式)
    Docker指令记录
    mysql 引擎
    G1调优随笔
    jvm面试题 新生代和 老年代的区别
    java虚拟机栈 相关操作
    .net大法总章
    .net趣味面试题总结
    IOC控制反转-依赖注入
  • 原文地址:https://www.cnblogs.com/superSmile/p/11209703.html
Copyright © 2011-2022 走看看