Pastate.js 响应式 react 框架之 模块化

本篇文章给大家分享的内容是关于pastate.js 响应式 react 框架之 模块化  ,有着一定的参考价值,有需要的朋友可以参考一下

这是 Pastate.js 响应式 react state 管理框架系列教程,欢迎关注,持续更新。

Pastate.js Github

模块化实战任务

如果应用比较复杂,有很多个页面,且一个界面具有比较多的组件和操作时,我们需要对应用划分模块 (Module) 进行管理。
下面我们以一个 班级信息管理系统 为例,介绍 pastate 应用的模块化机制。

实际体验:https://birdleescut.github.io/pastate-demo

应用源码: https://github.com/BirdLeeSCUT/pastate-demo

应用的原型如下:

(1) 学生板块

获取并显示学生信息

Pastate.js 响应式 react 框架之 模块化

修改学生信息

Pastate.js 响应式 react 框架之 模块化

(2) 课程板块: 显示课程信息

Pastate.js 响应式 react 框架之 模块化

这个应用相对比较简单,在实际开发中我们不一定需要对其进行模块化设计,在此我们只是用于介绍 pastate 模块化机制,让你知道如何用 pastate 处理足够复杂的应用。

模块划分

模块化设计的第一步就是模块划分,我们先从对我们的班级信息管理系统进行模块划分:

导航模块: Navigator

Pastate.js 响应式 react 框架之 模块化

学生信息模块: StudentPanel

Pastate.js 响应式 react 框架之 模块化

课程信息模块: ClassPanel

Pastate.js 响应式 react 框架之 模块化

pastate 模块构成

pastate 的模块机制是一种简洁的 flux 模式实现,一个 pastate 模块由三个基本元素构成:

状态 (state):保存模块当前的状态

视图 (view):模块状态的显示逻辑

动作 (action):模块动作的处理逻辑

这三个模块元素遵循如下的单向数据流过程:

Pastate.js 响应式 react 框架之 模块化

模块结构

我们通过一个文件夹组织一个模块,以 “学生信息模块” StudentPanel 为例,新建一个 StudentPanel 文件夹,并在文件夹下创建以下文件:

StudentPanel 模块文件夹

StudentPanel.model.js 模型文件:用于定义应用的 state 和 actions

StudentPanel.view.jsx 视图文件:用于定义的视图组件(组件渲染逻辑)

StudentPanel.css 样式文件:用于定义用于的样式(可以改用 less 或 sass)

模型文件 *.model.js

(1)设计模块的 state

我们先在模型文件 StudentPanel.model.js 下定义模块的 state 结构:
StudentPanel.model.js

const initState = {    initialized: false, // 初始化状态    /** @type { "loading" | "ok" | "error" } */    status: 'loading', // 加载状态    isEditting: false, // 是否在编辑中    selected: 0, // 选中的学生    /** @type {studentType[]} */    students: [] // 学生数组}const studentType = {    name: '张小明',    studentNumber: '2018123265323',    age: 22,    isBoy: true,    introduction: '我是简介'}...

登录后复制

与之前一样,我们通过配合 jsDoc 注释,把 state 结构的定义和初始值得定义一起进行。

Tips: 建议使用上面定义 status 属性的模式定义 “枚举字符串” 类型,对这种枚举值进行赋值时尽量采用 intelSence 的 “选择” 方法而非直接输入字符串,这可以为应用的开发带来方便并减少无畏的错误:赋值时把输入光标在等号后的引号中间按下 “触发提示” 快捷键即可显示选项:

Pastate.js 响应式 react 框架之 模块化

State mock 区域: 我们在开发视图时,需要对 state 的状态进行完备测试,比如要让 state.status 分别等于 “loading” | “ok” | “error” 、让 state.isEditting 等于 true | false 去完备地测试模块的渲染逻辑,这时我们不要直接更改 initState 的值,而是把 initState 下方作为一个 state mock 测试区域, 对 state 进行修改以实现 mock :

const initState = {...}const studentType ={...}/***** MOCK AREA *****/// initState.status = 'ok'// initState.isEditting = true// initState.students = [studentType, studentType]

登录后复制

你可以根据开发调试需求新建 mock 行,或通过注释控制某个 mock 行是否生效,以此来使应用处于某个中间 state 状态,方便调试。并在模块开发完成时把 mock 区域全部注释即可,这种模式可以有效地管理 mock 过程。

模块的 initState 是对模块的一种 “定义”,它具有“文档属性”,而 mock state 是对应用进行调试时执行的临时动态操作,如果通过直接修改 initState 来进行 mock,我们会破坏模块的定义,然后又尝试凭记忆对定义进行恢复,这个过程容易出错或遗漏,特别是当 state 变得复杂的时候。所以我们推荐采用 MOCK AREA 对 state 进行 mock 调试。

(2)定义模块的 actions

之前我们是把应用的动作逻辑实现为视图组件的成员函数,在应用简单时这种模式会比较直接方便,而当应用复杂且某些操作逻辑需要在不同组件甚至模块间共享时,原理的模式无法实现。因此我们把模块的相关操作逻辑统一放在 actions 中进行管理:

StudentPanel.model.js

const actions = {    init(){ },    loadStudents(){ },    switchEditting(){ },    /** @param {number} index 学生数组索引号 */    selectStudent(index){ },    increaseAge(){ },    decreaseAge(){ }}

登录后复制

在初步的  actions 声明阶段,我们只需把 actions 的名字和参数声明出来,在应用开发过程中再逐渐实现其业务逻辑。你可以考虑使用 jsDoc 对 action 的用途和参数进行注释说明。当模块简单的时候,你可以直接在 actions 中直接实现同步更新 state 的操作和异步从后台获取数据等操作,pastate 不对 actions 的实现的内容做限制,不需要像 redux 或 vuex 一样规定一定要把同步和异步逻辑的分开实现,在 pastate 中,当你认为有必要时才那样做就好了。

多级 actions  管理: 当模块的 actions 比较多的时候,我们可以采用多级属性的模式对 actions 进行分类管理, 具体的分类方法和分类级别根据具体需要自行定义即可,如下:

const actions = {    init(){ },    handle:{        handleBtnClick(){ },        handleXxx1(){ },        handleXxx2(){ }    },    ajax:{        getStudentsData(){ },        getXxx(){ },        postXxx(data){ }    }}

登录后复制

mutations 模式:  如果你的模块比较复杂,想遵循 redux 或 vuex 把对 state 同步操作  和 异步动作两类操作分类管理的模式,那么你可以对 state 的同步操作放在 actions.mutations 分类下,pastate 提供特殊中间件对 mutations 提供而外的开发调试支持,详见 规模化 章节。

const actions = {    init(){ },    handleBtnClick(){ },    getStudentsData(){ },    mutations:{        increaseAge(){ },        decreaseAge(){ }    }}

登录后复制

Mutations 其实就是一些同步的 state 更新函数,你可以通过其他普通 actions 调用 mutations, 或直接在视图中调用 mutations。比起 redux dispatch actions to reducers 和 vuex commit mutations 通过字符串 mutations 名称发起(dispatch) 的模式,这种函数调用的方式在开发时更加方便且不易出错:

无需为了调用方便,定义 actions / mutation 的常量名称

可以友好的支持 编辑器/ IDE 的智能提示

Pastate.js 响应式 react 框架之 模块化

如果你选择使用 pastate 的 mutations 机制,  那么每个 mutation 都要使用同步函数,不要在 mutation 中使用 ajax 请求或 setTimeout 或 Promise 等异步操作。这样相关的浏览器 devtools 才能够显示 有准确意义 的信息:

Pastate.js 响应式 react 框架之 模块化

这种 actions 分类管理的设计体现了 pastate 的精益原则:你能在需要某些高级特性的时候 才去能够 使用这些高级特性。

(3)创建并配置模块的 store

我们可以像之前那样简单地创建 store:
StudentPanel.model.js

import { Pastore } from 'pastate'const initState = {...}const actions = {...}...const store = new Pastore(initState);/** @type {initState} */let state = store.state;export { initState, actions, store}

登录后复制

Pastate 采用一种 可选的 的 actions 注入模式,你可以自愿决定是否把 actions 注入 store。 把 actions 注入 store 后,可利用 pastate 的中间件机制对 actions 进行统一管理控制,具有较强的可扩展性。例如我们可以使用 logActions 中间件对每次 actions 的调用在控制台进行 log,并使用  dispalyActionNamesInReduxTool 中间件 对把 mutations 名称显示出来,以便于调试:

import { ..., logActions, dispalyActionNamesInReduxTool } from 'pastate'...const store = new Pastore(initState);store.name = 'StudentPanel';store.actionMiddlewares = [logActions(), dispalyActionNamesInReduxTool(true)]store.actions = actions;/** @type {initState} */let state = store.state;export { initState, actions, store}

登录后复制

如果你觉得上面的定义方式比较琐碎,你可以直接使用 pastate 提供的工厂函数 createStore 来定义一个完整地 store:

import { ..., createStore, logActions, dispalyActionNamesInReduxTool } from 'pastate'const store = createStore({    name: 'StudentPanel',    initState: initState,    actions: actions,    middlewares: [logActions(), dispalyActionNamesInReduxTool(true)]})const { state } = store // createStore 具有良好的泛型定义,无需额外的 jsdoc 注释即可获取 state 的结构信息

登录后复制

你也可以进一步把中间件配置为仅在开发环境下生效的模式, 生产环境下无效。Pastate 中间件的详细内容请查看规模化章节。

视图部分

我们创建 StudentPanel.view.jsx 文件来保存我们的模块视图, 视图定义和原来的模式类似:
StudentPanel.view.jsx

import React from 'react'import { makeContainer, Input, Select} from 'pastate'import { initState, actions } from './StudentPanel.model'import './StudentPanel.css'const isBoyOptions = [{    value: true,    tag: '男'},{    value: false,    tag: '女'}]class StudentPanel extends React.PureComponent {    componentDidMount(){        actions.init()    }    render() {        let state = this.props.state        return (            

                {this['view_' + state.status](state)}            

        )    }    view_loading() {        return (            

                加载中...            

        )    }    view_error() {        return (            

                加载失败, 请刷新重试            

        )    }    /** @param {initState} state */    view_ok(state) {        let selectedStudent = state.students[state.selected];        return (            

                ...            

        )    }}export default makeContainer(StudentPanel)

登录后复制

Pastate 模块化需要实现一种多模块可以互相协作的机制。因此我们不再使用 makeOnyContainer 唯一地绑定一个视图组件与对应的 store。首先,我们会用各模块的 store 生成一个全局的 store 树,并使用 makeContainer 把模块的视图封装为引用全局 store 的某些节点的容器。

我们目前只有一个模块,此处简单地调用 makeContainer(StudentPanel)  让 StudentPanel 引用全局的 store 树 的根节点的 state ,我们可以为 makeContainer 指定第二个参数,指明引用 store 树 的哪些子节点,详情会在下一章介绍。

在上面视图组件的代码中,我们引入了 model 中的 actions:

import { store, initState, actions } from './StudentPanel.model'

登录后复制

这些 actions 可以直接赋值到组件的 onClick 或 onChange 等位置:

登录后复制

这些 actions 也可以在组件的生命周期函数中调用:

...componentDidMount(){    actions.init()}...

登录后复制

视图部分还包含样式文件 StudentPanel.css ,在此就不列出了。

如果该模块要需要封装一些当前模块专用的子组件,把子组件定义为独立的文件,并放在与 StudentPanel 模块相同的文件夹下即可。如果需要封装一些多个模块通用的非容器组件,可以考虑把它们放在独立于模块文件夹的其他目录。

导出模块

最后,为了方便调用,我们来为模块做一个封装文件 StudentPanel / index.js,导出模块的元素:

export { default as view } from './StudentPanel.view'export { store, actions, initState } from './StudentPanel.model'

登录后复制

pastate 模块向外导出 view, initState, actions, store 四个元素。

大功告成!这时我们可以尝试在 src / index.js 中引入该模块并渲染出来:

import ReactDOM from 'react-dom';import { makeApp } from 'pastate';import * as StudentPanel from './StudentPanel';ReactDOM.render(    makeApp(, StudentPanel.store),     document.getElementById('root'));...

登录后复制

我们使用 makeApp 函数创建一个 pastate 应用并渲染出来,makeApp 的第一个参数是 根容器,第二个参数是 store 树, 我们现在只有一个模块,所以应用的 store 树只有 StudentPanel 的 store。

自此,我们的第一个模块 StudentPanel 构建完成。

模块的模板文件

我们可以使用模板文件快速创建模块,一个模块的模板文件非常简单,下面以 TemplateModule 模块为例完整给出:

/index.js

export { default as view } from './TemplateModule.view'export { initState, actions, store } from './TemplateModule.model'

登录后复制

/TemplateModule.model.js

import { createStore } from 'pastate';const initState = {}const actions = {}const store = createStore({    name: 'TemplateModule',    initState,    actions})const { state } = storeexport { initState, actions, store }

登录后复制

/TemplateModule.view.jsx

import React from 'react';import { makeContainer } from 'pastate';import { initState, actions } from './ClassPanel.model';import './TemplateModule.css'class TemplateModule extends React.PureComponent{    render(){        /** @type {initState} */        const state = this.props.state;        return (            

                TemplateModule            

        )    }}export default makeContainer(TemplateModule, 'template')

登录后复制

/.css

// css 样式文件初始为空,你也可以选用 less 或 sass 来定义样式

登录后复制

这个例子的 demo 源码已包含该模板模块 src/TemplateModule, 你只需把它复制到你的 src 目录下,并右键点击模块文件夹,选择 “在文件夹中查找”,然后把 TemplateModule 字符串全部替换为你想要的模块名称即可:

Pastate.js 响应式 react 框架之 模块化

Pastate.js 响应式 react 框架之 模块化

点击替换之后保存文件。不过目前还不能自动替换文件名,需要手动替换一下。

Pastate 以后将会实现相关的命令行工具,实现一行命令创建新模块等功能,加速 pastate 应用的开发。

下一章,我们来创建另外的模块,并介绍不同模块之间如何协作。

相关推荐:

Pastate.js 响应式框架之数组渲染与操作

Pastate.js 响应式 react 框架之表单渲染与操作

Pastate.js 响应式框架之多组件应用

以上就是Pastate.js 响应式 react 框架之 模块化 的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2773872.html

(0)
上一篇 2025年3月8日 13:59:57
下一篇 2025年2月25日 00:54:37

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • JavaScript创建对象

    本篇文章给大家分享的内容是关于javascript创建对象,有着一定的参考价值,有需要的朋友可以参考一下 调用系统的构造函数 创建一个最简单的方式就是创建一个Object的实例,如下:     // 1. 调用系统的构造函数    var …

    编程技术 2025年3月8日
    200
  • 详解js中的遍历 问题

    本篇文章给大家分享的内容是关于详解js中的遍历 问题,有着一定的参考价值,有需要的朋友可以参考一下 实例属性和原型属性 JavaScript中对象的属性分为两种: 数据属性 和 访问器属性 。 根据具体的上下文环境的不同,又可以将属性分为:…

    编程技术 2025年3月8日
    200
  • 使用node.js构建命令行工具

    本篇文章给大家分享的内容是使用node.js构建命令行工具 ,有着一定的参考价值,有需要的朋友可以参考一下 工具说明 inquirer.js:一个封装了常用命令行交互的node.js模块,通过该模块可以很方便地构建一个新的命令行应用。 sh…

    编程技术 2025年3月8日
    200
  • Vue.js提升必知的几点总结

    这次给大家带来Vue.js提升必知的几点总结,Vue.js提升的注意事项有哪些,下面就是实战案例,一起来看一下。 第一招:化繁为简的Watchers 场景还原: created(){ this.fetchPostList()},watch:…

    编程技术 2025年3月8日
    200
  • 在vuejs中使用v-show不起作用的原因有哪些

    这次给大家带来在vuejs中使用v-show不起作用的原因有哪些,在vuejs中使用v-show的注意事项有哪些,下面就是实战案例,一起来看一下。 1.官网概念描述 v-if 是’真正的’条件渲染,因为它会确保在切换…

    编程技术 2025年3月8日
    200
  • vue对storejs获取数据进行处理的步奏详解

    这次给大家带来vue对storejs获取数据进行处理的步奏详解,vue对storejs获取数据进行处理的注意事项有哪些,下面就是实战案例,一起来看一下。 具体代码如下所示: export default { data(){ return {…

    编程技术 2025年3月8日
    200
  • JS怎样扩展字符串拼接

    这次给大家带来JS怎样扩展字符串拼接,JS扩展字符串拼接的注意事项有哪些,下面就是实战案例,一起来看一下。 1、题外话,有关概念理解:String.prototype 属性表示 String原型对象。所有 String 的实例都继承自 St…

    编程技术 2025年3月8日
    200
  • JS如何实现随机切换微信号

    这次给大家带来JS如何实现随机切换微信号,JS实现随机切换微信号的注意事项有哪些,下面就是实战案例,一起来看一下。 js代码: arr_wx =new Array(“aaaa”,”bbbb”,”cccc”); var wx_index = …

    编程技术 2025年3月8日
    200
  • AngularJS怎么重新加载路由页面

    这次给大家带来AngularJS怎么重新加载路由页面,AngularJS重新加载路由页面的注意事项有哪些,下面就是实战案例,一起来看一下。 用angular做项目,会碰到需要点击菜单刷新当前页面,加载当前页面,但是同一个路由页面点击没反应;…

    编程技术 2025年3月8日
    200
  • vue.js底部导航栏的子路由不显示怎么处理

    这次给大家带来vue.js底部导航栏的子路由不显示怎么处理,处理vue.js底部导航栏子路由不显示的注意事项有哪些,下面就是实战案例,一起来看一下。 最近利用vue第三方UI MuseUI开发webapp,然后在导航栏这里出现了问题,我需要…

    编程技术 2025年3月8日
    200

发表回复

登录后才能评论