reduxをパッケージ化して、より簡単に使えます.

29879 ワード

Redux
ReduxはJavaScript状態容器であり、予測可能な状態管理を提供する.
コンテンツリスト
  • モチベーション
  • コア概念
  • 三大原則
  • 先行技術
  • 基礎
  • Redux
  • JavaScript単一ページのアプリケーション開発はますます複雑になりました.state more--stateはいつ、どのように変化しますか?
  • は変化と非同期に分かれています.Reactはビュー層で非同期を禁止し、DOMを直接操作してこの問題を解決しようとしています.
  • ReduxはFluxから発展したが、Elmに触発されてFluxの複雑さ
  • を避けた.
  • Redux
  • は必要ないかもしれません.
    コア概念
    三大原則
  • 単一データソース:アプリケーション全体のstateは一株のobject treeに格納され、このobject treeは唯一のstoreにしか存在しない.
  • Stateは読み取り専用です.stateを変える唯一の方法はactionをトリガすることです.actionはイベントが発生したことを記述するための一般的なオブジェクトです.
  • は、純粋な関数を使用して修正を実行します.actionがどのようにstate treeを変えるかを説明するために、reducersを作成する必要があります.
  • 先行技術
  • Reduxは、Fuxの一実施形態と見なされてもいいですか?はい、違うとも言えます.
  • はFluxと同じで、Reduxはモデルの更新ロジックを全部一つの特定の層(Flux内のstore,Redux内のreducer)
  • に集中すると規定しています.
  • FuxとReduxは、プログラムが直接データを修正することを許可しない代わりに、「action」という普通のオブジェクトで変更について説明します.
  • はFuxとは違って、Reduxはdispatcherの概念がない(なぜなら、イベントプロセッサの代わりに純粋な関数に依存しているから).
  • とFluxのもう一つの重要な違いは、Reduxがあなたのデータを永遠に変えないと考えています.
  • Elmは関数式プログラミング言語で、(state,action)=>stateに従う規則を更新します.
    基礎
    action:イベント応答
    reducer:純関数、データ変更
    store:本当のstoreデータツリーを生成する

    app.js:
    
    import React from 'react';
    import ReactDOM from 'react-dom';
    import { HashRouter, Route } from 'react-router-dom';
    import { asyncComponent } from 'AsyncComponent';
    import HeaderMenu from './components/heard';
    import SiderMenu from './components/sider';
    import thunk from 'redux-thunk';
    import { createStore, applyMiddleware } from 'redux';
    import { Provider } from 'react-redux';
    import reducer from './reducer';
    import './css/main.css';
    
    const demo1 = asyncComponent(() => import(/* webpackChunkName: 'demo1' */ './demo1'));
    const demo2 = asyncComponent(() => import(/* webpackChunkName: 'demo2' */ './demo2'));
    
    let store = createStore(reducer, applyMiddleware(thunk));
    
    const router = (
    	
    		
    			
    ); ReactDOM.render(router, document.getElementById('content'));
    index.js:
    
    import React from 'react';
    import { connect } from 'react-redux';
    import { bindActionCreators } from 'redux';
    import { Layout, Breadcrumb, Button } from 'antd';
    import 'date-util';
    import ModalTip from 'modalTip';
    import { changeNeedCode } from './action';
    
    const { Content } = Layout;
    
    /**
     * demo1
     */
    
    const mapStateToProps = (state, ownProps) => {
    	return {
    		demo1Store: state.demo1Store
    	};
    };
    
    const mapDispatchToProps = (dispatch, ownProps) => {
    	return {
    		changeNeedCode: bindActionCreators(changeNeedCode, dispatch)
    	};
    };
    
    class demo1 extends React.Component {
    	componentDidMount() {
    		let that = this;
    		let changeNeedCode = that.props.changeNeedCode;
    		changeNeedCode('zhanghao');
    	}
    
    	render() {
    		let that = this;
    
    		return (
    			
    				
    					demo
    					demo1
    				
    				
    					
    {new Date().format('yyyy-MM-dd hh:mm:ss')}
    {that.props.demo1Store.welcomeText}
    {that.props.demo1Store.needCode}
    ); } _showModalTip(type) { switch (type) { case 'info': ModalTip.infoTip('info'); break; case 'success': ModalTip.successTip('success'); break; case 'error': ModalTip.errorTip('error'); break; case 'warning': ModalTip.warningTip('warning'); break; } } } export default connect(mapStateToProps, mapDispatchToProps)(demo1);
    action.js:
    
    import fetch from 'fetch/fetch';
    import ModalTip from 'modalTip';
    
    let checkNeedCode = nickName => {
    	let params = {};
    	params.nickName = nickName;
    	params.t = new Date().getTime();
    
    	return fetch
    		.post('/oauth/checkLogin', params)
    		.then(res => {
    			return res.needCode;
    		})
    		.catch(e => {
    			ModalTip.warningTip(e.message);
    		});
    };
    
    exports.changeNeedCode = nickName => async dispatch => {
    	let needCode = await checkNeedCode(nickName);
    	dispatch({ type: 'change_needCode', needCode: needCode });
    };
    
    
    reducer.js:
    
    import { combineReducers } from 'redux';
    
    const demo1Store = (state = { welcomeText: '', needCode: '' }, action = {}) => {
    	switch (action.type) {
    		case 'change_welcomeText':
    			return { ...state, welcomeText: action.welcomeText };
    		case 'change_needCode':
    			return { ...state, needCode: action.needCode };
    		default:
    			return { ...state };
    	}
    };
    
    const demo2Store = (state = { columnName: '', newsTitle: '', selectText: '   1', dUserCode: '' }, action = {}) => {
    	switch (action.type) {
    		case 'change_columnName':
    			return { ...state, columnName: action.columnName };
    		case 'change_newsTitle':
    			return { ...state, newsTitle: action.newsTitle };
    		case 'change_selectText':
    			return { ...state, selectText: action.selectText };
    		case 'change_dUserCode':
    			return { ...state, dUserCode: action.dUserCode };
    		default:
    			return { ...state };
    	}
    };
    
    export default combineReducers({
    	demo1Store: demo1Store,
    	demo2Store: demo2Store
    });
    
    
    Reduxm
    Reduxをよりよく使うために、二次パッケージを行います.
    コンテンツリスト
  • reduxに存在する問題
  • 設計思想
  • appi
  • 使用上の注意点
  • reduxに存在する問題
  • storeツリーがあります.ページを離れて再度ログインします.データは初期化されません.
  • .
  • reducer分割による集約困難
  • actionのtype管理が混乱し、問題を繰り返します.
  • 煩雑な使用規則、indexページactionとstoreは導入して、純粋な関数reducerの大量のcaseは一つの値を変えるためだけに
  • 設計思想(@修飾器)
  • connectstoreはReact Domにactionとstoreを注入し、componentWillUnmountライフサイクルを書き換え、ページを離れて自動トリガstore初期化
  • を開始する.
  • @修飾器、storeを使ってreducerに対して抽出してreducer factoryに預け入れて、actionはactionfactoryとactictory
  • に預け入れます.
  • actionのtypeはstoreの定義に従い、名前空間を隠してタイプの重複問題を解決し、及び隠しタイプの定義は大量case
  • を省略する.
    アプリ
        /**
         *      
         *   createStore、getDevTools、getActionType、getAllInitData    
         *
         * createStore  ,       react   
         * @params router(react  ), debug(        )
         * @return reactRouter
         *
         * getDevTools  ,        
         * @return DevTools(      )
         *
         * getActionType  ,  storeName   actionType
         * @param storeName(     )
         * @return {}(storeName   actionType)
         *
         * getAllInitData  ,  storeName       
         * @param storeName(     )
         * @return {}(storeName       )
         */
        import Store from './store/store';
        /**
         * store   ,    store       
         * @params storeName(     ), allActionType(        actionType), allStoreLogs(              )
         * @return true
         */
        const store = Store.store;
        /**
         * storeActionType   ,     actionType
         * @params actionType(      type), level(    )
         * @return target
         */
        const storeActionType = Store.storeActionType;
        /**
         * storeDestroy   ,           
         * @return target
         */
        const storeDestroy = Store.storeDestroy;
        
        /**
         * connectStore   ,    ,   reactDom
         * @params storeList[](         ), destroyStoreList[](           )
         * @return reactDom
         *         ReactDom   componentWillUnmount    
         *   
         *    ReactDom   componentWillUnmount            
         *        ReactDom
         *   
         * 	static componentWillUnmount (){
             	this._cons();
           	}
        
         _cons(){
                console.log("      ");
            }
         */
        import connectStore from './connect/connectstore';
        
        /**
         *      
         */
        import Action from './action/action';
        /**
         * action   ,    action       
         * @param actionName(     )
         * @return target
         */
        const action = Action.action;
        /**
         * actionProps   ,     action
         * @params actionFunName(    ), level(    )
         * @return target
         */
        const actionProps = Action.actionProps;
        /**
         * actionInjection   ,          reactDom
         * @param actionName(    )
         * @return target
         */
        const actionInjection = Action.actionInjection;
        
        export { Store, store, storeActionType, storeDestroy, connectStore, action, actionProps, actionInjection };
    
    使用上の注意点
  • はあなたのReactDomを引き継ぎ、componentWillUnmoutライフサイクルを書き換えるので、あなたのReact DomでcomponentWillUnmountライフサイクルを実現したいです.静的属性を加えなければなりません.コンテキストはまだReactDomです.
    static componentWillUnmount (){
             	this._cons();
           	}
        
    _cons(){
                console.log("      ");
            }
    
  • 使用を容易にするために、StoreでgetAllInitData方法を提供し、store Nameにおけるすべての初期データを取得し、手動でデータを初期化したい場合の重複性定義を低減する.
  • (dispatch、_this)、actionの中で第二のシステムレベルが参加して、_を提供します.thisは、action内部関数の相互呼び出しを容易にします.
  • app.jsルーティングファイルでは、次のような方法を使用したい場合:
  • (r => {
    	r.keys().forEach(r);
    })(require.context('./', true, /reducer\.js/));
    (r => {
    	r.keys().forEach(r);
    })(require.context('./', true, /action\.js/));
    
    を省略します.手動でreducerとactionを導入すると、すべてのページのコンポーネントは次のように非同期的に導入しなければなりません.
    const XXX = asyncComponent(() => import(/* webpackChunkName: 'XXX' */ './XXX'));
    
    非同期的にページコンポーネントを導入したくないなら、import{Store}from'reduxm'でなければなりません.とimport XXX from'.XXX';前に次のように紹介します.
    import './XXX/reducer';
    import './XXX/action';
    

    app.js:
    import React from 'react';
    import ReactDOM from 'react-dom';
    import { HashRouter, Route } from 'react-router-dom';
    import { asyncComponent } from 'AsyncComponent';
    import HeaderMenu from './components/heard';
    import SiderMenu from './components/sider';
    import 'date-util';
    import './css/main.css';
    
    (r => {
    	r.keys().forEach(r);
    })(require.context('./', true, /reducer\.js/));
    (r => {
    	r.keys().forEach(r);
    })(require.context('./', true, /action\.js/));
    
    import { Store } from 'reduxm';
    
    const demo1 = asyncComponent(() => import(/* webpackChunkName: 'demo1' */ './demo1'));
    const demo2 = asyncComponent(() => import(/* webpackChunkName: 'demo2' */ './demo2'));
    
    let debug = true;
    const router = Store.createStore(
    	
    		
    {debug ? Store.getDevTools() : null}
    , debug ); ReactDOM.render(router, document.getElementById('content'));
    index.js:
    import React from 'react';
    import { Layout, Breadcrumb, Button } from 'antd';
    import { connectStore, actionInjection } from 'reduxm';
    import ModalTip from 'modalTip';
    
    const { Content } = Layout;
    
    /**
     * demo1
     */
    
    @connectStore(['demo1Store'], ['demo1Store'])
    @actionInjection('demo1Action')
    export default class demo1 extends React.Component {
    	componentDidMount() {
    		this.props.changeNeedCode('zhanghao');
    		this.props.changeImmutableList(this.props.demo1Store);
    	}
    
    	render() {
    		let that = this;
    
    		console.log(that.props.demo1Store.immutableList);
    		console.log(that.props.demo1Store.immutableList.toJS());
    
    		console.log(that.props.demo1Store.immutableInList.immutableList[0]);
    		console.log(that.props.demo1Store.immutableInList.immutableList[0].toJS());
    
    		return (
    			
    				
    					demo
    					demo1
    				
    				
    					
    {new Date().format('yyyy-MM-dd hh:mm:ss')}
    {that.props.demo1Store.welcomeText}
    {that.props.demo1Store.needCode}
    ); } _showModalTip(type) { switch (type) { case 'info': ModalTip.infoTip('info'); break; case 'success': ModalTip.successTip('success'); break; case 'error': ModalTip.errorTip('error'); break; case 'warning': ModalTip.warningTip('warning'); break; } } }
    action.js:
    import fetch from 'fetch/fetch';
    import ModalTip from 'modalTip';
    import { Store, action, actionProps } from 'reduxm';
    import immutable from 'immutable';
    
    const demo1Type = Store.getActionType('demo1Store');
    const demo1AllInitStore = Store.getAllInitData('demo1Store');
    
    let checkNeedCode = nickName => {
    	let params = {};
    	params.nickName = nickName;
    	params.t = new Date().getTime();
    
    	return fetch
    		.post('/oauth/checkLogin', params)
    		.then(res => {
    			return res.needCode;
    		})
    		.catch(e => {
    			ModalTip.warningTip(e.message);
    		});
    };
    
    @action('demo1Action')
    class demo1Action {
    	@actionProps('changeNeedCode')
    	static changeNeedCode = nickName => async (dispatch, _this) => {
    		let needCode = await checkNeedCode(nickName);
    		dispatch({ type: demo1Type.change_needCode, needCode: needCode });
    	};
    
    	@actionProps('changeImmutableList', 'error')
    	static changeImmutableList = demo1Store => async (dispatch, _this) => {
    		let immutableList = demo1Store.immutableList;
    		let immutableInList = demo1Store.immutableInList;
    
    		immutableList = immutable.set(immutableList, 0, 4);
    		immutableInList.immutableList[0] = immutable.set(immutableInList.immutableList[0], 0, 10);
    
    		dispatch({
    			type: demo1Type.change_demo1Store,
    			demo1Store: {
    				immutableList: immutableList,
    				immutableInList: immutableInList
    			}
    		});
    
    		demo1AllInitStore.welcomeText = 'www---www';
    		console.log(demo1AllInitStore);
    	};
    }
    
    reducer.js:
    import { store, storeActionType, storeDestroy } from 'reduxm';
    import immutable from 'immutable';
    
    @store('demo1Store', 'change_demo1Store')
    class demo1 {
    	@storeActionType('change_welcomeText')
    	@storeDestroy
    	static welcomeText = 'Welcome to Redux test!';
    
    	@storeActionType('change_needCode')
    	@storeDestroy
    	static needCode = 1;
    
    	@storeActionType('change_immutableList', 'waring')
    	@storeDestroy
    	static immutableList = immutable.fromJS([1, 2, 3]);
    
    	@storeActionType('change_immutableInList')
    	@storeDestroy
    	static immutableInList = {
    		immutableList: [immutable.fromJS([7, 8, 9])]
    	};
    }