目录
更新 state 结构
分别开发 basicInfo 和 address 的视图组件
store.imState 与 store.state
使用 props 接收 imState,实现组件的按需渲染
使用 imState 渲染视图的注意事项
了解 PureComponent
子组件 state 的 intelliSense
单实例子组件
首页 web前端 js教程 Pastate.js 响应式框架之多组件应用

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

Apr 10, 2018 pm 04:20 PM
javascript 组件

本篇文章给大家分享的内容是关于Pastate.js 响应式框架之多组件应用  ,有着一定的参考价值,有需要的朋友可以参考一下

这是 pastate 系列教程的第二章,欢迎关注,持续更新。

这一章,我们在上一章的 state 结构中添加多一些信息,并用多个组件来组织 pastate 应用。

更新 state 结构

我们把上一章的个人基本信息数据包装为 state.basicInfo 属性的对象,并向 state 中添加 address 属性,保存个人地址信息:

const initState = {
    basicInfo: {
        name: 'Peter',
        isBoy: true,
        age: 10
    },
    address: {
        country: 'China',
        city: 'Guangzhou'
    }
}
登录后复制

由于 JavaScript 语言的限制,pastate 不能检测到通过赋值来为对象添加新属性,以自动把新属性转化为响应式节点。所以你应该在 initState 中把需要用到的 state 属性都定义出来,把属性值初始化为 null 或空数组都是可以的。下面是个错误的例子

const initState = {
    basicInfo: ...,
    address: ...
}
const store = new Pastore(initState)
const state = store.state

state.hobby = 'coding'  // 错误,state.hobby 属性不具有受 pastate 控制,不具有响应式特点
登录后复制

即使支持这种特性,它也会使开发者难以完全把握 state 的结构,导致应用难以开发和维护,所以我们应该在 initState 里对 state 的结构进行完整的定义。

分别开发 basicInfo 和 address 的视图组件

我们先使用一种简单临时的方式来构建子组件:

...
/** @type {initState} */
const state = store.state;

class BasicInfoView extends Component {
    render(){
        return (
            <p style={{padding: 10, margin: 10}}>
                <strong>Basic info:</strong><br/>
                My name is {state.basicInfo.name}.<br/>
                I am a {state.basicInfo.isBoy == true ? "boy" : "girl"}.<br/>
                I am {state.basicInfo.age} years old.<br/>
            </p>
        )
    }
}
登录后复制
class AddressView extends Component {
    render(){
        return (
            <p style={{padding: 10, margin: 10}}>
                <strong>Address:</strong><br/>
                My country is {state.address.country}.<br/>
                My city is {state.address.city}.<br/>
            </p>
        )
    }
}
登录后复制

可以看到,BasicInfoView 组件直接引用 store.state.basicInfo 的值,AddressView 组件直接引用 store.state.address 的值。接着修改原来的 AppView 父组件,把这两个子组件嵌套进去,同时增加一个方法来修改 address.city 的值:

...
class AppView extends Component {
    increaseAge(){
        state.basicInfo.age += 1
    }
    decreaseAge(){
        state.basicInfo.age -= 1
    }
    changeCity(){
        state.address.city += &#39;!&#39;
    }
    render() {
        return (
            <p style={{padding: 10, margin: 10, display: "inline-block"}}>
                <BasicInfoView />
                <AddressView />
                <button onClick={this.decreaseAge}> decrease age </button> 
                <button onClick={this.increaseAge}> increase age </button> 
                <button onClick={this.changeCity}> change city </button>
            </p>
        )
    }
}
...
登录后复制

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

完成!让我们运行一下:

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

点击按钮,看起来一切正常!我们通过 Chrome 的 react dev tools 来观察一下当 state 改变时,各个组件的渲染情况。打开浏览器的开发者工具,选择 react 标签,勾选上 Highlight Updates, 这时当组件重新渲染时,会被带颜色的方框框起来。

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

我们点击页面上 decrease age 按钮试试,组件重新渲染的结果如下:

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

我们可以发现,当只有 state.basicInfo.age 更改时,AppView、BasicInfoView 和 AddressView 3个组件都会被重新渲染,即使 AddressView 所引用的数据没有发生任何改变!这是 react 多组件渲染的通常情况,当应用组件简单、嵌套层级不多时,我们不会感觉到这种模式会带来什么明显的影响;但是当应用组件的嵌套关系变得比较复杂的时候,会带来性能隐患,我们需要来关注这个问题。

store.imState 与 store.state

先介绍一下 store 中的两个不同的 state:store.imStatestore.state ,你可以尝试了解一下:

  • store.imState 是应用状态的数据实体,它被 pastate 使用 immutable 的机制进行管理,当节点的内容更新时,该节点的所有祖先的“引用”都会被更新。imState 的每个节点值除了 null 或 undefined 外,都是包装类型(String, Number, Boolean, Object, Array)。

  • store.state 是 store.imState 的 响应式影子, 可以对 store.state 任何节点进行直接赋值修改,pastate 会把修改结果作用到 store.imState,并异步触发视图更新。

或者简化为以下两点:

  • store.imState 用来渲染视图

  • store.state 用来操作数据

这两个概念对于没有使用过 redux 和没了解过 vue.js 原理的人来说可能有点难以理解。不过没关系,不理解这两个概念并不妨碍你使用 pastate,你可以在使用 pastate 的过程中完全感觉不到 imState 的存在。pastate 的理念就是封装复杂概念,让你可以用一种简单的方式去实现复杂的功能。

如果你想要理解 pastate 的详细原理,可以查看原理章节。

使用 props 接收 imState,实现组件的按需渲染

当一个 component 与 store 连接时,store 会把 imState 传递到 component 的 props
.state 中,因此我们可以在 AppView 组件的 props 中接收 state,同时把 AppView 组件的基类改为 react 纯组件 PureComponent,这样就开启了组件按需渲染效果:

import React, { PureComponent } from &#39;react&#39;; // 1. 改用 PureComponent 代替 Component
...
class AppView extends PureComponent { // 1. 改用 PureComponent
    ...
    render() {
        /** @type {initState} */
        let state = this.props.state; // 2. 从 props 接收 state
        return (
            <p style={{padding: 10, margin: 10, display: "inline-block"}}>

                {/**  3. 把 state 的子节点传递给对于的子组件 */}

                <BasicInfoView state={state.basicInfo}/>
                <AddressView state={state.address}/>
                ...
            </p>
        )
    }
}
...
登录后复制

注意上面代码的第3点注释,我们把 state 数据的子节点通过 props 传递给子组件:
<BasicInfoView state={state.basicInfo}/>。对于不直接与 store 直接连接的子组件,我们同样也需要修改为从
props 获取 state, 并把组件的基类改成 PureComponent:

class BasicInfoView extends PureComponent { // 1. 基类改为 PureComponent
    render(){
        let state = this.props.state; // 2. 从 props 接收 state
        return (
            <p style={{padding: 10, margin: 10}}>
                <strong>Basic info:</strong><br/>

                {/**  3. 这里的 state 是 basicInfo 对象 */}

                My name is {state.name}.<br/>
                I am a {state.isBoy == true ? "boy" : "girl"}.<br/>
                I am {state.age} years old.<br/>
            </p>
        )
    }
}
登录后复制
class AddressView extends PureComponent { // 1. 基类改为 PureComponent
    render(){
        let state = this.props.state;  // 2. 从 props 接收 state
        return (
            <p style={{padding: 10, margin: 10}}>
                <strong>Address:</strong><br/>

                {/**  3. 这里的 state 是 address 对象 */}

                My country is {state.country}.<br/>
                My city is {state.city}.<br/>
            </p>
        )
    }
}
登录后复制

可以看到,分配到子组件的 props 中的 state 是 根state 的子节点。因此在 BasicInfoView 中的 this.props.state 是 basicInfo 对象, 而在 AddressView 中的 this.props.state 是 address 对象。

完成!我们来看看运行效果!

  • 点击 decrease age 按钮或 increase age 按钮,我们看到的组件重新渲染情况是:

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

  • 点击 change city 按钮,我们看到的组件重新渲染情况是:

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

Amazing!可以看到当我们点击按钮改变 state 节点时,只有引用被改变的 state 节点的组件才会进行重新渲染, 我们成功地实现了多组件按需渲染的效果!当应用具有大量不与 store 直接连接的子组件时,这种按需渲染的策略可以大幅提高应用的渲染性能。

使用 imState 渲染视图的注意事项

从 props 中接收到的 state 的每个节点都是特殊的包装类型 , 当需要在 if(...) 语句或 ... ? A : B 使用其布尔值结果时, 需要使用 == 进行显式比较来获取,如下

class BasicInfoView extends PureComponent {

    render() {
        /** @type {initState[&#39;basicInfo&#39;]} */
        let state = this.props.state;
        return (
            <p style={{ padding: 10, margin: 10 }}>

               {state.isBoy == true ? "boy" : "girl"}  {/* 正确 */}
               {state.isBoy ? "boy" : "girl"}  {/* 错误 */}

               {state.age != 0 ? "Not 0" : "0"}  {/* 正确 */}
               {state.age ? "Not 0" : "0"}  {/* 错误 */}

            </p>
        )
    }
}
登录后复制

了解 PureComponent

React 的 PureComponent 会在渲染前对新的 props / state 与老的 props / state 进行浅层比较( shallow comparison),仅当发现 props / state 发生改变时,才执行重新渲染。浅层比较即是比较 props / state 的根级属性值是否改变,如果属性值是数组 / 对象类型,比较的结果使其引用是否相等:

console.log(["a"] == ["a"]) // 结果是 false

let a = ["a"]
console.log(a == a) // 结果是 true
登录后复制
console.log({a: "a"} == {a: "a"}) // 结果是 false

let a = {a: "a"} 
console.log(a == a) // 结果是 true
登录后复制

Pastate 符合 immutable data 规范的 state 数据,可以确保当某个 state 节点改变时,其祖先节点的引用都会进行更新,所以可以配合使用 PureComponent 实现高效的按需渲染。

按需渲染时需要对 state 的结构进行模块化设计,如果把所有的属性都放在 state 根节点上,就没法实现按需渲染了:

// 注意:这样的 state 设计无法实现子组件的按需渲染
initState = {
     name: &#39;Peter&#39;,
     isBoy: true,
     age: 10,
     country: &#39;China&#39;,
     city: &#39;Guangzhou&#39;
}
登录后复制

当然,只有当应用的 state 比较复杂且对 state 的操作比较繁多时候,才会体现按需渲染对性能的提升;当应用比较简单的时候,不一定要对 state 和视图进行太详细的划分。

子组件 state 的 intelliSense

同样,我们可以使用 jsDoc 注释让子组件中 state 的具有智能提示,如下:

class BasicInfoView extends PureComponent {
    render(){
        /** @type {initState[&#39;basicInfo&#39;]} */
        let state = this.props.state;
        ...
    }
}
登录后复制
class AddressView extends PureComponent {
    render(){
        /** @type {initState[&#39;address&#39;]} */
        let state = this.props.state;
        ...
    }
}
登录后复制

请使用 xxx['xxx'] 的格式指明对象的子节点: /** @type {initState[&#39;address&#39;]} */。在 vs code 里,暂时无法使用 xxx.xxx 的嵌套格式指定一个变量的类型。

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

单实例子组件

如果某组件只在视图中出现一次,那么这种组件被称为单实例组件。这种组件可以把对子组件设计的 state 操作函数简单地封装在子组件内部,提高组件的内聚性,便于维护管理。下面以 BasicInfoView 为例,把操作按钮移入子组件,并把两个操作函数移入子组件

...
class BasicInfoView extends PureComponent {

    increaseAge(){
        state.basicInfo.age += 1
    }
    
    decreaseAge(){
        state.basicInfo.age -= 1
    }

    render(){
        /** @type {initState[&#39;basicInfo&#39;]} */
        let state = this.props.state;
        return (
            <p style={{padding: 10, margin: 10}}>
                ...
                <button onClick={this.decreaseAge}> decrease age </button> 
                <button onClick={this.increaseAge}> increase age </button> 
            </p>
        )
    }
}
...
登录后复制

同样,你也可以对 AddressView 做类似的处理。

下一章, 我们将会介绍如何在 pastate 中渲染和操作 state 中的数组。


这是 pastate 系列教程的第二章,欢迎关注,持续更新。

这一章,我们在上一章的 state 结构中添加多一些信息,并用多个组件来组织 pastate 应用。

相关推荐:

Pastate.js 之响应式 react state 管理框架

以上是Pastate.js 响应式框架之多组件应用 的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何安装Win10旧版本组件DirectPlay 如何安装Win10旧版本组件DirectPlay Dec 28, 2023 pm 03:43 PM

不少用户在玩win10的的一些游戏的时候总是会遇到一些问题,比如说卡屏和花屏等等情况,这个时候我们是可以采用打开directplay这个功能来解决的,而且功能的操作方法也很简单。win10旧版组件directplay怎么安装1、在搜索框里面输入“控制面板”然后打开2、查看方式选择大图标3、找到“程序和功能”4、点击左侧的启用或关闭win功能5、选择旧版这里的勾选上就可以了

如何使用WebSocket和JavaScript实现在线语音识别系统 如何使用WebSocket和JavaScript实现在线语音识别系统 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript实现在线语音识别系统引言:随着科技的不断发展,语音识别技术已经成为了人工智能领域的重要组成部分。而基于WebSocket和JavaScript实现的在线语音识别系统,具备了低延迟、实时性和跨平台的特点,成为了一种被广泛应用的解决方案。本文将介绍如何使用WebSocket和JavaScript来实现在线语音识别系

WebSocket与JavaScript:实现实时监控系统的关键技术 WebSocket与JavaScript:实现实时监控系统的关键技术 Dec 17, 2023 pm 05:30 PM

WebSocket与JavaScript:实现实时监控系统的关键技术引言:随着互联网技术的快速发展,实时监控系统在各个领域中得到了广泛的应用。而实现实时监控的关键技术之一就是WebSocket与JavaScript的结合使用。本文将介绍WebSocket与JavaScript在实时监控系统中的应用,并给出代码示例,详细解释其实现原理。一、WebSocket技

如何利用JavaScript和WebSocket实现实时在线点餐系统 如何利用JavaScript和WebSocket实现实时在线点餐系统 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket实现实时在线点餐系统介绍:随着互联网的普及和技术的进步,越来越多的餐厅开始提供在线点餐服务。为了实现实时在线点餐系统,我们可以利用JavaScript和WebSocket技术。WebSocket是一种基于TCP协议的全双工通信协议,可以实现客户端与服务器的实时双向通信。在实时在线点餐系统中,当用户选择菜品并下单

如何使用WebSocket和JavaScript实现在线预约系统 如何使用WebSocket和JavaScript实现在线预约系统 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript实现在线预约系统在当今数字化的时代,越来越多的业务和服务都需要提供在线预约功能。而实现一个高效、实时的在线预约系统是至关重要的。本文将介绍如何使用WebSocket和JavaScript来实现一个在线预约系统,并提供具体的代码示例。一、什么是WebSocketWebSocket是一种在单个TCP连接上进行全双工

Angular组件及其显示属性:了解非block默认值 Angular组件及其显示属性:了解非block默认值 Mar 15, 2024 pm 04:51 PM

Angular框架中组件的默认显示行为不是块级元素。这种设计选择促进了组件样式的封装,并鼓励开发人员有意识地定义每个组件的显示方式。通过显式设置CSS属性 display,Angular组件的显示可以完全控制,从而实现所需的布局和响应能力。

如何打开win10旧版组件的设置 如何打开win10旧版组件的设置 Dec 22, 2023 am 08:45 AM

win10旧版组件是需要用户自己去设置里面打开的,因为很多的组件平时都是默认关闭的状态,首先我们需要进入到设置里面,操作很简单,跟着下面的步骤来就可以了win10旧版组件在哪里打开1、点击开始,然后点击“win系统”2、点击进入控制面板3、再点击下面的程序4、点击“启用或关闭win功能”5、在这里就可以选择你要的打开了

JavaScript和WebSocket:打造高效的实时天气预报系统 JavaScript和WebSocket:打造高效的实时天气预报系统 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的实时天气预报系统引言:如今,天气预报的准确性对于日常生活以及决策制定具有重要意义。随着技术的发展,我们可以通过实时获取天气数据来提供更准确可靠的天气预报。在本文中,我们将学习如何使用JavaScript和WebSocket技术,来构建一个高效的实时天气预报系统。本文将通过具体的代码示例来展示实现的过程。We

See all articles