[react-control-center tutorial 2] 動態配置模塊

目錄回顧react


今天咱們將經過此文告訴cc用戶,除了startup,cc也提供configure來配置模塊相關信息哦^_^

啓動時配置模塊

經過啓動cc咱們知道,能夠在startup時將模塊的storereducercomputedinit一次性配置好

以下例子,咱們定義兩個模塊loginproduct,以及重寫cc的內置模塊$$global

  • login模塊相關代碼
// code in models/login/index.js
import reducer from './reducer';
import state from './state';
import init from './init';
export default {reducer, state, init}
複製代碼
// code in models/login/state.js
export default {
    loading:false,
    onlineCount:0,
    failReason:'',
    uid:0,
    username:'',
    role:'',
}
複製代碼
// code in models/login/reducer.js
import api from 'service/user';
function changeLoading(loading){
    return {loading}
}
async function loginWithPassword({payload:{username,password}, dispatch}){
    await dispatch('login/changeLoading', true);
    // 等價於寫  await dispatch({module:'login', type:'changeLoading', payload:true});
    // 備註,若是這裏肯定來來自於login模塊的組件實例調用的this.$$dispatch('updatePassword',{uid,password})
    // 這裏還能夠簡寫爲dispatch('changeLoading', true),由於此dispatch句柄默認是去改變的模塊就是觸發該updatePassword函數的$$dispatch調用實例所屬的模塊
    
    const {success, message, data} = await api.loginWithPassword(username,password);
    if(success){
        const {uid, username, role, customizedBorderColor} = data;
        //派發到$$global模塊修改相應的狀態
        dispatch('$$global/changeBorderColor', customizedBorderColor);
        return {loading:false, uid, username, role};
    }else return {loading:false, failReason:message};
}
async function updatePassword({payload:{uid,password}, dispatch}){
    await dispatch('login/changeLoading', true);
    const {success, message, data} = await api.updatePassword(uid,password);
    if(success) return {loading:true};
    else return {loading:false, failReason:message};
}
export default {
    changeLoading,
    loginWithPassword,
    updatePassword,
}
複製代碼
//code in models/login/init.js
import api from 'service/userApi';
export default setState=>{
    api.getOnlineCount().then(onlineCount=>{
        setState({onlineCount});
    });
}
複製代碼
  • product模塊相關代碼
// code in models/product/index.js
import reducer from './reducer';
import state from './state';
export default {reducer, state}
複製代碼
// code in models/product/state.js
export default {
    loading:false,
    pageSize:10,
    currentPage:0,
    totalPage:0,
    totalCount:0,
    productList:[],
}
複製代碼
// code in models/product/reducer.js
import api from 'service/product';
import cc from 'react-control-center';
function changeLoading(loading){
    return {loading}
}
async function _fetchProduct(currentPage, pageSize){
    const {list:productList, totalCount} = await api.fetchProduct(currentPage, pageSize);
    const totalPage = Math.ceil(totalCount/pageSize);
    return {productList, totalCount, totalPage};
}
async function nextPage({dispatch, moduleState}){
    await dispatch('changeLoading', true);
    const {currentPage, pageSize} = moduleState;
    const nextPage = currentPage+1;
    const {productList, totalCount, totalPage} = await _fetchProduct(nextPage, pageSize);
    return {loading:false, productList, totalCount, totalPage, currentPage:nextPage};
}
async function prevPage({dispatch, moduleState}){
    await dispatch('changeLoading', true);
    const {currentPage, pageSize} = moduleState;
    const nextPage = currentPage-1;
    const {productList, totalCount, totalPage} = await _fetchProduct(nextPage, pageSize);
    return {loading:false, productList, totalCount, totalPage, currentPage:nextPage};
}
async function changePageSize({dispatch, moduleState, payload:pageSize}){
    await dispatch('changeLoading', true);
    const {currentPage} = moduleState;
    const {productList, totalCount, totalPage} = await _fetchProduct(currentPage, pageSize);
    return {loading:false, productList, totalCount, totalPage, pageSize};
}
async function refreshCurrentPage({dispatch, moduleState}){
    await dispatch('changeLoading', true);
    const {currentPage, pageSize} = moduleState;
    const {productList, totalCount, totalPage} = await _fetchProduct(currentPage, pageSize);
    return {loading:false, productList, totalCount, totalPage};
}
//上傳統計用戶的刷新行爲,由於該函數不返回任何新的state,將不觸發cc組件實例的渲染
function uploadRefreshBehavior(){
    const loginModuleState = cc.getState('login');
    const {uid} = loginModuleState
    api.uploadRefreshBehavior({uid, action:'refreshCurrentPage'});
}
//cc並不強制要求每個reducer函數都返回一個新的片段state,該方法經過dispatch組合了另外兩個reducer函數
function refreshCurrentPageAndTrack({dispatch}){
    dispatch('refreshCurrentPage');
    dispatch('uploadRefreshBehavior');
}
export default {
    changeLoading,
    nextPage,
    prevPage,
    changePageSize,
    refreshCurrentPage,
    uploadRefreshBehavior,
    refreshCurrentPageAndTrack,
}
複製代碼
  • $$global模塊相關代碼
// code in models/global/index.js
import reducer from './reducer';
import state from './state';
import computed from './computed';
export default {reducer, state, computed}
複製代碼
// code in models/global/state.js
export default {
    customizedBorderColor:'#FFFFFF',
}
複製代碼
// code in models/global/reducer.js
function changeBorderColor({payload:customizedBorderColor}){
    return {customizedBorderColor};
}
複製代碼
//code in models/global/computed.js
export default {
    customizedBorderColor(customizedBorderColor){
        return `1px solid ${customizedBorderColor}`;
    }
}
複製代碼

將他們配置到cc的StartUpOption

// code in startup-cc.js
import loginModel from 'models/login';
import productModel from 'models/product';
import globalModel from 'models/global';
import cc from 'react-control-center';

function myMiddle1(executionCotext, next){
    console.log(executionCotext);
    // here write your code
    next();
}
function myMiddle2(executionCotext, next){
    console.log(executionCotext);
    // here write your code
    next();
}

const models = [
    {module:'login',model:loginModel},
    {module:'product',model:productModel},
    {module:'$$global',model:globalModel},
];

const store={}, reducer={}, init={}, computed={};
models.forEach(item=>{
    const {module, model:{state, reducer:_reducer, init:_init, computed:_computed}} = item;
    if(state)store[module]=state;
    if(_reducer)reducer[module]=_reducer;
    if(_init)init[module]=_init;
    if(_computed)computed[module]=_computed;
});

cc.startup({
    isModuleMode:true,
    store,
    reducer,
    init,
    computed,
    // 注意,此處配置了中間件函數,任何cc實例觸發了改變state的行爲,
    // cc都會前調用中間件函數鏈而後纔開始改變state, 爲第三方編寫插件預留了可操做入口,例如計劃中的rcc-state-changging-logger
    middlewares:[myMiddle1, myMiddle2]
});
複製代碼

動態配置模塊

cc一樣支持在startup以後,經過cc.configure動態的添加新的模塊(注意,此方法必定要在startup後調用哦),以上代碼能夠改造爲

// code in startup-cc.js
import cc from 'react-control-center';
function myMiddle1(executionCotext, next){
    console.log(executionCotext);
    // here write your code
    next();
}
function myMiddle2(executionCotext, next){
    console.log(executionCotext);
    // here write your code
    next();
}
cc.startup({
    isModuleMode:true,
    middlewares:[myMiddle1, myMiddle2]
});
複製代碼
// code in configure-cc.js
import loginModel from 'models/login';
import productModel from 'models/product';
import globalModel from 'models/global';
import cc from 'react-control-center';

const models = [
    {module:'login',model:loginModel},
    {module:'product',model:productModel},
    {module:'$$global',model:globalModel},
];

const store={}, reducer={}, init={}, computed={};
models.forEach(item=>{
    const {module, model:{state, reducer:_reducer, init:_init, computed:_computed}} = item;
    const option = {};
    if(_reducer)option.moduleReducer = _reducer;
    if(_init)option.init=_init;
    if(_computed)option.computed=_computed;
    cc.configure(module, state, option);
});
複製代碼
//code in App.js
import 'startup-cc.js';//注意此處必定是先引入startup-cc.js
import 'configure-cc.js';
複製代碼

cc.configure一樣也能夠不須要在一處文件裏集中式的調用,這樣方便用戶按照本身的習慣和理解來組織代碼

  • 此時用戶的文件結構可能以下
|________components
|     |________Login
|     |     |________model
|     |     |     |________state.js
|     |     |     |________reducer.js
|     |     |     |________init.js
|     |     |     |________index.js
|     |     |________index.js
複製代碼
  • components/Login/model/index.js裏負責完成cc.configure的調用
import moduleReducer from './reducer';
import state from './state';
import init from './init';
import cc from 'react-control-center';
cc.configure('login', state, {moduleReducer, init});
複製代碼
  • components/Login/index.js裏引用components/Login/model,觸發cc動態加載login模塊
// code in components/Login/index.js
import React from 'react';
import cc from 'react-control-center';
import './model';

@cc.register('Login',{module:'login', sharedStateKeys:'*'});
export default class Login extends React.Component{
    //......
}
複製代碼

總結,cc彈性的設計cc.configure方便用戶靈活和組織代碼和配置模塊,同時也方便用戶開發本身的cc組件發佈到npm,這樣其餘用戶引用你的組件時,不須要勾出你的stateinitcomputed等屬性配置在StartUpOption


附:cc化的ant-design-pro裏的models替換git

相關文章
相關標籤/搜索