npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mvc-react

v0.1.9

Published

mvc-react

Downloads

29

Readme

mvc-react

reactreduxrouter 的基础上实现新一代 MVC 的一套解决方案,可以摆脱大量繁杂的配置过程。

相关依赖: react-router-controllerreact-router-redux-saga-modelredux-saga-model

初览-第一印象

import React from 'react';
import { render } from 'react-dom';
import { BrowserMVC as MVC, Controller } from 'mvc-react';

function modelRegister(register) {
	//register model or else
}

function renderApp() {
  render(<MVC modelRegister={modelRegister} />, document.getElementById('root'));
}

// start
renderApp();

install

$ npm i mvc-react

or

$ yarn add mvc-react

角色

首先我们将传统的 MVC 模式与我们的 MVC 模式进行对比。

传统的 MVC 模式:

MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。

mvc-react 与传统的 MVC 模式相比较有几点不同:

  1. 传统的 view 不负责交互逻辑,由 controller 处理交互逻辑并更新 model 数据。 而我们使用了 react 作为我们的 view 层,完全可以在 react 组件中写与用户的交互逻辑。
  2. 传统的 model 与 view 一样不负责交互逻辑,只负责数据的维护,这里我们使用了 redux-saga-model 的思想,将其作为 model 层。由于 model 中的 saga 拥有极强的流程控制能力( 底层使用的是 redux-saga ),所以我们完全可以把比较复杂的交互逻辑抽取放在 model 层,此时我们的 model 即具有数据维护的能力也具备实现复杂交互逻辑的能力,再进一步的细分我们还可以将 model 细分成两部分( dataModel、viewModel)
  3. 传统的 controller 除了实现交互逻辑还负责路由的控制,mvc-react 的 Controller 只实现路由功能不参与其他逻辑 。

mvc-react 与传统的 MVC 模式比较的相同点:

  1. 当 model 的数据发生了变化时通知 view 进行及时更新。
  2. 一样是 model 层对数据负责,不同的 model 负责不同纬度亦或不同业务逻辑相关的数据。

mvc-react 的组件交互图:

如何使用

Controller

在开发中我们最常做的就是区分模块,Controller 也一样,你可以根据你的需要来划分 controller 的纬度。

在 mvc-react 中,controller 实际上是对路由的高阶抽象,在 controller 中,你可以选择对外开放什么页面以及开放哪些页面。

mvc-react 底层封装了 react-router-controller ,该组件实现了 URL 与 controller 以及对应的 View 的动态映射规则。

使用该功能只需要提前提供一个参数对象给 Controller 的静态 set 方法即可:

  Controller.set({
    readViewFile(viewId) {
      //view可以异步载入
      return import(`./view/${viewId}/index.jsx`).then(component => {
        return component.default;
      });
    },
    readControllerFile(controllerId) {
      //webpackMode: eager是使import变为不异步,跟require一样,
      return import(/* webpackMode: "eager" */
      `./controller/${controllerId}.js`)
        .then(controller => {
          return controller.default;
        })
    },
    //设置首页path(跳转路径,即react-router path='/'时,会跳转到indexPath)
    indexPath: '/main/index',
  });

这样当每次 URL 发生变更时,只要符合映射规则就会执行上述通用流程,并获取对应的 controller ,以及 View 然后展示给用户。

controller 的配置规则如下:

import Controller from 'react-router-controller';

export default class MainController extends Controller {
  indexView(params) {
    return this.render(
      {
        title: '主页',
        breadcrumbs: [],
      },
      params
    );
  }
}

很明显这里采用了类的写法,首先引入基类 Controller 然后写下对外开放的 viewId 对应的方法名,譬如这里对外开放的 viewId 为 index,则对应的方法名为 indexView。更多细节查看该框架的使用入门

Model

mvc-react 底层封装了 redux-saga-model ,每个 model 内都有 reducerssagas ,reducers 中的 reducer 维护 redux 的 model namespace 下的数据块,每个 reducer 都输纯函数,不包括副作用,而 sagas 中的每个 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,
        });
    }
  }
}

篇幅有限,这里不对 model 进行细入的讲解,重点讲如何在 mvc-react 中使用上述的这些 model。

我们回看初栏-第一印象中的代码:

import React from 'react';
import { render } from 'react-dom';
import { BrowserMVC as MVC, Controller } from 'mvc-react';
import model from 'model/index/db.js'

function modelRegister(register) {
	//register model or else
  	register(model);
}

function renderApp() {
  render(<MVC modelRegister={modelRegister} />, document.getElementById('root'));
}

// start
renderApp();

我们只需要在 mvc 组件中注入一个 modelRegister 回调,即可拿到入参,注册 model 的方法 register 对 model 进行注册。

配合 Controller 中的介绍,我们可以写出动态加载 controller 以及 view 组件的同时动态注册 model 的代码。

import React from 'react';
import { render } from 'react-dom';
import { BrowserMVC as MVC, Controller } from 'mvc-react';

function modelRegister(register) {
  
  // Controller.set 设置如何读取指定模块的过程
  // 譬如如何根据一个 controllerID 加载一个 controller 组件,如何根据一个 viewID 加载一个 view 组件

  Controller.set({
    readViewFile(viewId, firstLoad) {
      if (firstLoad) {
        import(/* webpackMode: "eager" */
        `./model/${viewId}.js`)
          .then(model => {
            //注册sagaModel
            register(model.default);
          });
      }
      //view 可以异步载入
      return import(`./view/${viewId}/index.jsx`).then(component => {
        return component.default;
      });
    },
    readControllerFile(controllerId) {
      //webpackMode: eager是使import变为不异步,跟require一样,
      return import(/* webpackMode: "eager" */
      `./controller/${controllerId}.js`)
        .then(controller => {
          return controller.default;
        });
    },
    //设置首页path(跳转路径,即 react-router path='/'时,会跳转到indexPath)
    indexPath: '/main/index',
  });
}

function renderApp() {
  render(<MVC modelRegister={modelRegister} />, document.getElementById('root'));
}

// start
renderApp();

注意:配置 controller 规则的 Controller.set 方法必须在项目启动时同步执行,不支持异步配置。 modeRegister 是同步执行的,故可以在 modeRegister 回调中放入 Controller.set。

View

有了上面强大的 Controller 和 Model ,对于 View 而言,我么可以写出非常轻量级的组件,在 react 组件中,当需要触发对应的后续处理时,只需要分发对应的 action 即可,对应 namespace 的 model 会对其进行捕获,并更新数据,重新触发 view 的渲染更新。

import React from 'react';
import { connect } from 'react-redux';

@connect(state => {
  return {
    display: state.index,
  };
})
export default class AboutView extends React.Component {
  showToggleEvent = e => {
    const { dispatch, display } = this.props;
    if (display) {
      dispatch({
        type: 'index/toggleShow',
        payload: false,
      });
    } else {
      dispatch({
        type: 'index/toggleShow',
        payload: true,
      });
    }
  };
  render() {
    const { display } = this.props;
    return (
      <div>
        当前位置主页页面:
        <button onClick={this.showToggleEvent}>
          {display ? '隐藏' : '显示'}
        </button>
        {display && <div>我被显示了</div>}
      </div>
    );
  }
}

其他

  1. 项目打包工具: webpack

  2. 项目启动工具:create-react-boilerplate-app