【问题探讨】H5 UI渲染心智模型
目标
探讨H5 UI渲染心智模型,即阐述数据是依据什么样的逻辑渲染到界面上的。
本文思路
先通过一个示例讲述不同的数据渲染逻辑,然后讲两个延伸DEMO来着重说明CLASS和FUNCTION的特点;
示例,实现如下一个时钟,页面加载时开始1s跳动一次
实现
一,原生JS直接操作DOM
index.html
<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>React App</title></head><body><!-- 写一个div元素标签用于挂载数据 --><div id="root" /><script type="text/javascript" src="./index.js"></script></body>
</html>
index.js
(() => { // 获取用于挂载数据的元素标签const root = document.getElementById('root')setInterval(() => {// 获取当前系统时间const currentTime = new Date( +new Date() + 8 * 3600 * 1000 ).toJSON().slice(0,19).replace("T"," ")// 将系统时间挂载到元素标签上root.innerText = "当前系统时间是:" + currentTime},1000)
})()
二,通过框架(vue、react、angular等)实现DATA => DOM同步
DATA CHNAGE => 生成新的虚拟DOM,比较与旧DOM 之间的DIFF => DOM CHANGE
1.1,CLASS组件的特点
带有实例this和生命周期(创建,更新,销毁等周期)的组件,组件所有内容(包括数据)都挂在this上,通过this可以获取的组件的最新状态。
1.2,CLASS组件实现时钟
import React from 'react';class ProfilePage extends React.Component {state={time: ''}componentDidMount() {setInterval(() => {// 获取当前系统时间const currentTime = new Date( +new Date() + 8 * 3600 * 1000 ).toJSON().slice(0,19).replace("T"," ")// 将系统时间赋值给statethis.setState({time: currentTime})},1000)}render() {return <div>{this.state.time}</div>;}
}export default ProfilePage;
2.1,FUNCTION组件的特点
没有实例和生命周期的纯函数组件,没有this,数据由hooks维护,可使用Hooks模拟生命周期特性;
什么是 Hooks?
Hooks 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。
什么是useState?
在这里,useState 就是一个 Hook。通过在函数组件里调用它来给组件添加一些内部 state。
什么是useEffect?
a,你之前可能已经在 React 组件中执行过数据获取、订阅或者手动修改过 DOM。我们统一把这些操作称为“副作用”,或者简称为“作用”。
b,useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的触发时机,只不过被合并成了一个 API。
c,当你调用 useEffect 时,就是在告诉 React 在完成对 DOM 的更改后运行你的“副作用”函数。由于副作用函数是在组件内声明的,所以它们可以访问到组件的 props 和 state。默认情况下,React 会在每次渲染后调用副作用函数 —— 包括第一次渲染的时候。
// 触发时机等于componentDidMount+componentDidUpdate useEffect(() => {// do some thing})
// 添加依赖后,触发时机等于componentDidMountuseEffect(() => {// do some thing},[])
// 添加return后,,return的触发时机等于componentWillUnmount useEffect(() => {// do some thingreturn () => {// 触发时机等于componentWillUnmount}}, [])
2.2,FUNCTION组件实现时钟
import React, {useState, useEffect} from 'react';function ProfilePage() {const [time, changeTime] = useState('')useEffect(() => {setInterval(() => {// 获取当前系统时间const currentTime = new Date( +new Date() + 8 * 3600 * 1000 ).toJSON().slice(0,19).replace("T"," ")// 将系统时间赋值给statechangeTime(currentTime)},1000)},[])return (<div>{time}</div>);
}export default ProfilePage;
三,延伸DEMO
1,关注demo
点击关注,关注某个人的主页
1.1 公共代码
import React from "react";import ProfilePageFunction from './ProfilePageFunction';
import ProfilePageClass from './ProfilePageClass';class App extends React.Component {state = {user: '凌云',};render() {return (<><label><b>选择你想浏览的主页: </b><selectvalue={this.state.user}onChange={e => this.setState({ user: e.target.value })}><option value="凌云">凌云</option><option value="晓林">晓林</option><option value="江江">江江</option></select></label><h1>欢迎来到 {this.state.user}的 个人主页!</h1><p><ProfilePageFunction user={this.state.user} /><b> (function组件)</b></p><p><ProfilePageClass user={this.state.user} /><b> (class组件)</b></p></>)}
}
export default App;
1.2,CLASSS实现
import React from 'react';class ProfilePage extends React.Component {showMessage = () => {alert('已关注:' + this.props.user);};handleClick = () => {setTimeout(this.showMessage, 3000);};render() {return <button onClick={this.handleClick}>关注</button>;}
}export default ProfilePage;
1.3,FUNCTION实现
import React from 'react';function ProfilePage(props) {const showMessage = () => {alert('已关注: ' + props.user);};const handleClick = () => {setTimeout(showMessage, 3000);};return (<button onClick={handleClick}>关注</button>);
}export default ProfilePage;
1.4,正常情况下没问题,做一个特殊操作
在凌云的主页点击关注,然后在3秒内切换到晓林的主页。
此时,function组件正常;
class组件异常,3秒后,提示关注了晓林。
原因就是上面讲的:
CLASS组件数据挂载在this上,this是在时刻变化的。
处理方式1(其他处理方式不再展开),在发起关注时缓存关注的user
import React from 'react';class ProfilePage extends React.Component {showMessage = (user) => {alert('已关注:' + user);};handleClick = () => {const user = this.props.usersetTimeout(() => {this.showMessage(user)}, 3000);};render() {return <button onClick={this.handleClick}>关注</button>;}
}export default ProfilePage;
2,自增DEMO
实现一个一秒加一的自增计数功能
2.1, 公共代码
import React from "react";import ProfilePageFunction from './ProfilePageFunction';
import ProfilePageClass from './ProfilePageClass';class App extends React.Component {render() {return (<><div><b> (function)</b><ProfilePageFunction /></div><div><b> (class)</b><ProfilePageClass /></div></>)}
}
export default App;
2.2 CLASS实现
import React from 'react';class ProfilePage extends React.Component {state={count: 0}componentDidMount() {setInterval(() => {// 组件挂载时开启定时器,一秒加一this.setState({count: this.state.count + 1})},1000)}render() {return <div>{this.state.count}</div>;}
}export default ProfilePage;
2.3 FUNCTION实现
import React, {useState, useEffect} from 'react';function ProfilePage() {const [count, changeCount] = useState(0)useEffect(() => {setInterval(() => {// 组件挂载时开启定时器,一秒加一changeCount(count + 1)},1000)}, [])return (<div>{count}</div>);
}export default ProfilePage;
2.4,运行后发现
CLASS实现正常,
FUNCTION实现异常:界面从0到1之后,就不走了
原因是:
添加 [ ] 依赖后的useEffect的确在触发时机上和componentDidMount一样,只会在function组件第一次渲染的时候执行一次,后面不再执行,但是它因为没有this,所以这里面拿到的count永远都是初始count=0;
useEffect(() => {setInterval(() => {// 组件挂载时开启定时器,一秒加一changeCount(count + 1)},1000)}, [])
处理方式1(其他方式不再展开),使用 useRef 来跨越渲染周期存储数据(但是它和 useState 的区别,除了可以跨越渲染周期存储数据,同时对它修改也不会引起组件重新渲染)
import React, {useState, useEffect, useRef } from 'react';function ProfilePage() {const [count, changeCount] = useState(0)const coutRef = useRef(0)const startAdd = () => {setInterval(() => {// 一秒加一coutRef.current = coutRef.current + 1changeCount(coutRef.current)},1000)}useEffect(() => {// 组件挂载时开启定时器startAdd()}, [])return (<div>{count}</div>);
}export default ProfilePage;
参考文档:
1, Dan Abramov博客: 函数式组件与类组件有何不同?
https://overreacted.io/zh-hans/how-are-function-components-different-from-classes/
2,react官方文档:使用Effect Hook
https://react.docschina.org/docs/hooks-effect.html
【问题探讨】H5 UI渲染心智模型相关推荐
- DirectX12(D3D12)基础教程(七)——渲染到纹理、正交投影、UI渲染基础
目录 1.前言 2.渲染到纹理 3.调试支持 4.正交投影 5.UI渲染基础 6.本章完整代码链接 1.前言 记得那是在差不多10多年前,我在工作中认识了一位好兄弟小杨.那时他刚毕业,跟我是同一所大学 ...
- React 的心智模型
本文是 React 核心开发者 Sebastian Markbåge 撰写,阐述了他设计 React 的初衷及与 React 相关的最基础的理论概念.阅读此文,你能站在更高的高度去思考关于 React ...
- 2.react心智模型(来来来,让大脑有react思维吧)
人人都能读懂的react源码解析(大厂高薪必备) 2.react心智模型(来来来,让大脑有react思维吧) 视频课程&调试demos 视频课程的目的是为了快速掌握react源码运行的过程 ...
- Web3 网络效应:五种心智模型
Web3 网络效应:五种心智模型 在过去的十年里,网络效应推动了Web2平台的崛起,也奠定了其主导地位,同时激发了建设者和投资者的想象力.一些人认为网络效应在Web3中会更加强大,而另一些人则认为We ...
- 【Unity基础】UI——小地图的制作 UI界面显示人物模型
小地图的制作 [思路] 小地图的主要思路是用摄像机拍摄以人物为中心的一小步部分区域,把拍摄的图片实时渲染到UI界面的Img图片上. 首先需要一个摄像机 , 用来垂直拍摄人物的头顶,把模式改成正交模式, ...
- 心智模型四剑客 之 MEC与攀梯术
http://piglili.blogbus.com/ 一.攀梯术是什么? 攀梯术是一种一对一深访中使用的探询(probing)技术,用于挖掘人们如何利用某些概念来组织他们关于某事/物的想法,以及这些 ...
- OPhone 3D开发之解析渲染MS3D模型
OPhone 3D开发之解析渲染MS3D模型 OPhone平台中,3D模块已经成为一项标准配置,而且随着硬件成本的降低,搭配硬件加速图形芯片 的移动设备也越来越多地出现在人们的视野当中,手机上的3D再 ...
- Unity中如何通过UI显示3D模型解决方案?
需求:实现将3D模型显示在2DUI上面,实现王者荣耀英雄商城之中英雄展示功能,3D模型可以旋转,添加特效等正常3D功能. 使用RenderTexture和RawImage做相机映射 使用ScreenS ...
- 函数式组件与类组件区别-心智模型
与React类组件相比,React函数式组件究竟有何不同? 区别:心智模型不同,函数式组件捕获了渲染所用的值. 函数式组件与类组件有何不同? - Overreacted他们是完全不同的宝可梦哦.htt ...
最新文章
- 我不知道风是在哪一个方向吹
- ubuntu 18.10无法locate boot-repair
- 纯英文换行的css,利用CSS实现纯英文数字自动换行
- 关于QTP 9.2 .NET 插件破解的尝试
- 更换mysql-connector-java-6.0.5jar包后程序出现的两个异常及解决方法
- CF618F Double Knapsack 构造、抽屉原理
- DBI接口和DPI接口的区别
- SharePoint Designer 2010中的外部内容类型-SQL Server
- mysql碎片data free_浅析MySQL数据碎片的产生(data free)
- java实现gps定位_GPS定位数据的提取与存储系统的设计
- [架构之路-42]:目标系统 - 系统软件 - Linux下的网络通信-2-无线局域网WIFI原理、WIFI与3G/4G/以太网/蓝牙的协议转换
- Mac下Android 反编译
- Lumion 9.0 动画渲染的10个技术技巧
- Java 接收OutLook 微软邮箱邮件
- torch.nn.MSELoss的用法
- spring boot整合微信支付
- 什么叫死区时间_关于pwm死区时间的介绍
- PDPS软件:机器人固定点焊虚拟仿真操作方法
- electron-vue通过配置文件设置baseUrl
- 数据仓库和数据集市的概念、区别与联系