Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

redux-saga-model

Package Overview
Dependencies
Maintainers
1
Versions
55
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

redux-saga-model

此项目为从 [`dva`](https://github.com/dvajs/dva) 中抽取出对 model 的处理。

  • 0.2.11
  • Source
  • npm
  • Socket score

Version published
Maintainers
1
Created
Source

redux-saga-model

此项目为从 dva 中抽取出对 model 的处理。

npm i --save redux-saga-model

or

yarn add redux-saga-model

why

在 redux 的初期使用中,我们在 react 组件中进行异步处理,并在 then 中同步分发 action,在 reducer 中实时更新数据,但这样容易出现冗余代码且不易于后期维护,后前我们使用了 redux-thunk ,将每个 thunk 作为异步处理的流程块 ,随着业务的复杂我们发现对于更复杂的流程控制,redux-thunk 也是力不从心,接着我们发现了 redux-saga,并对其强大的异步处理流程控制着迷,但这个时候我们发现我们的每个模块单元下的目录结构如下:

|
  |--components/
  |--action.js
  |--reducer.js
  |--router.js
  |--selector.js
  |--saga.js
  |...

我们发现了 dva,这个强大的框架将 saga.js 与reducer.js 进行了有效的结合:

|
  |--components/
  |--action.js
  |--model.js
  |--router.js
  |--selector.js
  |...

每个 model 都有独立的维护机制,各自负责属于自己的一块 state-tree。每个 model 将对其独立的 state-tree 进行维护的 reducers 进行封装,同时把负责业务逻辑的 saga 放入 model 中,并为每个 model 增加 namespace 。看起来的确很完美,但是我们发现其中这个 model (我们统称为 saga-model) 的处理( dva )与 react 进行了捆绑,同时由于我们有一套自己实现的项目启动工具,想要将这个 saga-model 的优秀思想进行结合。故我们将其进行抽取,同时进行改造。

改变

  • 独立出来的 model 处理器称为 sagaModel ,通过实例化 SagaModel 拿到 sagaModel。

  • 可以很明显的入参 initialState initialReducer initialMiddleware 而不需要 dva 那样晦涩。

  • ​ 每个 model 中的代码结构如下:

    {
      namespace:'index',
      state:{
        name:'Tim'
      },
      reducers:{
        update:function(state,{payload}){
          return{ ...state,name:payload.name };
        }
      },
      sagas:{
        *updateName({payload},effects){
          yield effects.put({
              type:'update',
              payload,
            });
        }
      }
    }
    

    可以发现与 dva 的 model 基本一致,但是把 dva 中的 model 的 effects 字段换成了 sagas 因为根据 redux-saga 的官方文档介绍,这个叫法更符合其用意。

    同理,在 plugins 中,也将 dva 中的 onEffect 改成了 onSaga

    this.hooks = {
      onError: [],
      onStateChange: [],
      onAction: [],
      onHmr: [],
      onReducer: [],
      onSaga: [],
      extraReducers: [],
      extraEnhancers: [],
    };
    
  • 在每个 model 内的 saga,默认执行类型是 takeEvery 可以像 dva 一样将每个 saga 传入数组格式,更换其执行类型:

    {
      namespace:'index',
      state:{
        name:'Tim'
      },
      reducers:{
        update:function(state,{payload}){
          return{ ...state,name:payload.name };
        }
      },
      sagas:{
        updateName:[*({payload},effects)=>{
          yield effects.put({
              type:'update',
              payload,
            });
        },{ type: 'takeEvery' }],
        updateAddress:[*({payload},effects)=>{
          yield //...
        },{ type: 'takeLatest' }]
      }
    }
    

    支持的类型与 dva 相同 watcher takeLatest throttle takeEvery 默认是 takeEvery 在 dva 中,每个 saga 都允许省略当前 model 的 namespace 前缀直接分发( put )当前 reducer 的名字作为 actionType ,但是同样的特性不支持 take( 在 watcher 中自己决定接受什么 action),这里将其改进为支持该特性。

    {
      namespace:'index',
      state:{
        name:'Tim'
      },
      reducers:{
        update:function(state,{payload}){
          return{ ...state,name:payload.name };
        }
      },
      sagas:{
        watchUpdateName:[*({payload},effects)=>{
          // yield effects.take('index/update_name');
          yield effects.take('update_name');
          yield effects.put({
              type:'update',
              payload,
            });
        },{ type: 'watcher' }],
    }
    
  • 为每个 saga 以及 reducer 内部的 this 提供指向当前的 model。

  • 不再提供与 react,react-router 的绑定,在 dva 中可以直接 start 启动,而这里需要你自己根据实际情况进行处理, 实例化 SagaModel 后通过 sagaModel 的 store 方法获取配置完成的 store,自己进行下一步的处理,如需要与 react-router 进行绑定,可以参考 react-router-redux-saga-model 以及其对应的案例。

  • API 的命名改变,具体如下。

API

  • SagaModel model 处理器类,处理过程与 dva基本相似,入参均为可选:

    • initialState :Object 传入 createStore 的默认 state

    • initialReducer :Object 不包含在 model 中的其他 reducers

    • initialMiddleware :Array 其他 middleware, logging 等各种

    • initialModels :Array 在获取 store 时启动所有的 model,正常情况下推荐使用改默认入参将所有的 model 进行启动,如果需要异步启动可以使用 sagaModel.register 方法。

    • history :Object 通过 history 构造的实例,可以用于在 model 的 substrtions 中使用。

    import {SagaModel} from 'redux-saga-model';
    const sagaModel = new SagaModel({initialState, initialReducer, initialMiddleware, initialModels,history});
    
    const store = sagaModel.store();
    
  • sagaModel.use 使用插件

    import sagaModel from 'redux-saga-model';
    import someCrossSliceReducer from 'somewhere';
    import reduceReducers from 'reduce-reducers'
    
    sagaModel.use({
        onReducer:(reducer)=>{
          return reduceReducers(reducer, someCrossSliceReducer);
        },
        onError:(error,dispatch)=>{
          // ... 统一捕获所有异常
        }
      	//...
    })
    

    插件类型:如前面所述,基本与 dva 一致,除了把 onEffect 改成了 onSaga

    hooks = {
      onError: [],
      onStateChange: [],
      onAction: [],
      onHmr: [],
      onReducer: [],
      onSaga: [],
      extraReducers: [],
      extraEnhancers: [],
    }
    
  • sagaModel.plugin 获取所有插件

    import sagaModel from 'redux-saga-model';
    
    const plugins = sagaModel.plugin();
    
  • sagaModel.setHistory 设置 history

    import createBrowserHistory from "history/createBrowserHistory";
    import sagaModel from 'redux-saga-model';
    
    sagaModel.setHistory(createBrowserHistory());
    
  • sagaModel.history 获取 history

    import createBrowserHistory from "history/createBrowserHistory";
    import {ConnectedRouter} from "react-router-redux";
    import sagaModel from 'redux-saga-model';
    
    sagaModel.setHistory(createBrowserHistory());
    
    export default (props)=>{
        return (
        	<ConnectedRouter history={sagaModel.history()}>
              { props.children }
            </ConnectedRouter>
        );
    }
    
  • sagaModel.store 获取配置完成的 store,并启动所有的已存在的 models

    import {Provider} from "react-redux";
    import sagaModel from 'redux-saga-model';
    import APP from './app';
    
    export default ()=>{
        return (
          <Provider store={sagaModel.store()}>
            <APP />
          </Provider>
      );
    }
    
  • sagaModel.register 注册一个 model,可以在任何时刻调用。 sagaModel.register(models,hot) :

    • models : 可以是单个 model 也可以是数组形式的 models
    • hot :任意非空值 这里的非空是指 not undefined ,not null 你可以设置为 true 或时间戳等任意格式,这里的 hot 代表是否处于热替换状态下,当且仅当在获取 store 后注册 model ,处于热替换状态且下会存在重新执行指定代码块的情况故会重新注册 model。若非热替换状态下(不传 hot 参数)重复注册相同 model则会引发 namespace 重复 异常。
    import sagaModel from 'redux-saga-model';
    import userModel from 'users/userModel';
    import indexModel from 'index/indexModel';
    import todoModel from 'todo/todoModel';
    
    sagaModel.register(indexModel);
    
    const store = sagaModel.store();
    
    sagaModel.register(todoModel);
    
    //sagaModel.register([indexModel,todoModel]);
    
    new Promise((resolve,reject)=>{
        setTimeout(()=>{
            sagaModel.register(userModel);
          	resolve();
        },1000);
    });
    
  • sagaModel.dump 卸载一个指定 namespace 的 model

    import userModel from 'users/userModel';
    import sagaModel from 'redux-saga-model';
    
    sagaModel.register(userModel);
    sagaModel.dump(userModel.namespace);
    
  • sagaModel.models 获取所有的 models

    import sagaModel from 'redux-saga-model';
    
    console.log(sagaModel.models().length);
    
  • 其他内部 API

  • store 上的挂载 为了支持方便的异步注册,在 store 上挂载了 registerdump 方法

    import sagaModel from 'redux-saga-model';
    const store = sagaModel.store();
    
    //somewhere
    const {register,dump} = store;
    
    //somewhere maybe react
    const {register,dump} = this.context.store;
    

用例

react-router-redux-saga-model

指南

redux-saga-model-tutorial

FAQs

Package last updated on 24 Nov 2017

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc