React核心思维模型(一)

一、数据和视图分离,数据改变驱动视图更新

<div>Tom</div>

如果我们想修改上述div盒子中的Tom为Jerry,应该怎样修改呢 

在jquery中我们直接把界面元素抓过来修改

document.getElementsByTagName('div').item(0) = 'Jerry'

但在react中,当需要更改用户界面时,在绝大多数情况下,我们都是去操作数据,而不是直接更改界面元素(DOM 节点)。当数据变动以后,相应的界面元素会自动更改。

<div>{state}</div>
const [state, setState] = useState('Tom')
setState('Jerry')

注意:在用 React 写界面时,先写一些 HTML 作为页面的静态结构,再用大括号标记,加入动态的、可交互的元素,记住,永远只关注数据!!

拓展:受控组件和非受控组件

当一个 input 关联了一个数据项(比如 state),我们称之为受控组件。其他可交互的 HTML 元素跟 input 情况类似,比如 select 和 textarea。

与受控组件相对应,另有一种组件被称为非受控组件,也就是说其状态不受 React 控制。

绝大多数情况下,我们都使用受控组件,非受控组件一般用于 state 无法表达控件状态的情况,比如,支持文件上传框:<input type="file" />

二、声明式、命令式和响应式

1.命令式:

传统的Web编程方式,比如jquery和浏览器API,需要我们一步一步下达明确的指令,考虑实现细节,在脑中跟踪系统内部状态,什么时候创建DOM元素,调用哪个Web API等等

示例打开对话框步骤

1.对话框是否存在?

2.如果不存在就创建对话框div,添加button

3.调整样式为display:block

2.声明式:

新生代Web框架,比如React、Vue.js以及SQL语言和CSS,我们只需要描述想要的结果,具体实现细节交给react本身,可以专注于业务逻辑

//绑定动态数据

const [visible ,setVisible] = useState(false)

//打开对话框

setVisible(true)

{visible && <div>对话框</div>}

注意:声明式其实是命令式的一种抽象,react底层本身也肯定调用了很多命令式的DOM API,所有声明式语言或者框架都是以某种命令式的实现为基础的

3.响应式

声明式和响应式是react的基本特征

当数据发生变化时,react将自动对相关DOM元素做相应的调整,看起来就像是DOM响应了数据变化的号召而自发地做出地更改,所以声明式是响应式的基础

react不算完全意义上的响应式,因为还需要我们调用set函数进行更改,而在Vue中,我们确实可以做到直接修改变量的值实现界面的改动

react的这种方式虽然会相对繁琐一点,但是在查找bug更方便,因为可以一直沿着函数调用栈追溯到肇事的代码                

三、JSX详解

1.JSX理解

JSX是伪装成HTML的JavaScript代码,JSX 标签实际上是一个函数调用

在发送到浏览器执行之前, React 开发工具将 JSX 标签自动转换为相应的 JavaScript 代码。

例子一

<div>Tom</div>

跟下面的代码是等效的

import {jsx as _jsx} from 'react/jsx-runtime'
function App() {
  return _jsx("div", { children: "Tom" })
}

在App函数里,我们调用了_jsx函数并且返回其结果,这个函数接收了两个参数:"div"和{children:"Tom" }

 例子二

<div className="mr-wall" />

//等价于

_jsx("div", { className: "mr-wall" })

这个函数调用仍然有两个参数,第一个参数是元素的类型,第二个参数则是包含了所有属性的一个对象。

例子三

<div>
  <button />
</div>

//等价于

_jsx('div', { children: _jsx('button') })

children 是一个特殊的属性,包含了嵌套在 div 里的标签,或者说是 div 的“孩子”。而 button 同时也是一个 jsx 标签,所以 children 的值是再一次调用 _jsx 的结果。

例子四

<div className="container">
  <div className="mr-wall"> {alan} </div>
  <button />
</div>

转换成 JavaScript:

_jsx('div', { className: "container", children: [
  	_jsx("div", { className: "mr-wall", children: [" ", alan, " "] }), 
	  _jsx('button')
]})

2.JSX返回值

_jsx 函数所创建并返回了一个简单的 JavaScript 对象,这个对象的正式名称是 React 元素

function App() {
  const result = _jsx("input")
  console.log(result) // 打印到控制台
  return result
}

上述代码的打印结果是

Object {type: "input", key: null, ref: null, props: Object, _owner: null}

既然是函数调用,JSX 标签就是一个 JavaScript 表达式,可以写在任何能容纳表达式的地方。可以将JSX 标签赋值给一个变量,或者作为参数在调用函数时传过去,或者打印在控制台上。

3.JSX 和 HTML 的区别

举例比较

// JSX
<input style={{ minWidth: 200 }} />
  
// HTML
<input style="min-width: 200px" />

为什么有两层大括号呢?

  • 外层大括号让 JSX 识别这是 JavaScript
  • 内层大括号定义了样式对象,minWidth: 200是一个键值对

 再看一个例子,HTML 的按钮是这样写的:

<button onclick="alert('OK')">OK</button>

当用户点击按钮时,onclick 属性中的代码会被执行,alert('OK') 作为一个字符串被当作 JavaScript 代码执行。

而 JSX 版本则是这样的:

<button onClick={() => alert("OK")}>OK</button>

 改成JavaScript:

_jsx('button', { onClick: () => alert('OK')}, "OK")

当用户点击这个按钮时,会触发 onClick 属性中定义的函数,() => alert('OK') 作为一个函数被当作 JavaScript 代码执行。

其他区别:

特性JSXHTML
语法类似于 JavaScript,允许使用表达式标准的标记语言,不支持 JavaScript 表达式
组件支持组件(如 <MyComponent />只支持 HTML 元素,没有组件概念
属性命名使用 camelCase(如 className使用小写字母(如 class
注释使用 {/* 注释内容 */}使用 <!-- 注释内容 -->
自闭合标签必须自闭合(如 <img />可以有自闭合形式(如 <img>
事件处理通过 camelCase 属性(如 onClick使用小写字母(如 onclick
表达式支持 JavaScript 表达式(如 {value}仅支持固定文本,不支持 JavaScript
风格写法使用对象语法(如 style={{ color: 'red' }}使用字符串(如 style="color: red;"
条件渲染使用三元运算符或逻辑与(如 {condition ? <Component /> : null}不支持条件渲染,需用 JavaScript 控制逻辑
版本控制使用 Babel 转换为 JavaScript直接由浏览器解析

4.JSX的参数

(1)属性值,如: <input value={text} />

如果作为属性值,那么这个“洞”里就可以放任何表达式,只要相应的组件能够处理,比如变量、函数、函数调用(JSX标签)

<div>{<input type="text" />}</div>     

可以这样书写,不过大括号有点多余

(2)标签的嵌套内容,如:<div>{content}</div>

如果是作为标签的嵌套内容,那么该表达式的值就不能是一个对象(React 元素除外)。例如

function App() {
  const content = { name: '艾伦', age: 25 }
  return <div>{content}</div>
}

浏览器上就会出现如下错误:

Error
Objects are not valid as a React child (found: object with keys {name, age}). If you meant to

举例:map遍历标签数组

以下两种写法是等价的,当大括号内表达式为数组时,JSX会把数组内容解释为标签的“孩子”

// 1
<select>
  {[<option>艾伦</option>, <option>汉堡</option>]}
</select>

// 2
<select>
  <option>艾伦</option>
  <option>汉堡</option>
</select>

因此 

function App() {
  const snacks = ['艾伦', '汉堡']
  return (
    <select>
      { snacks.map(snack => <option>{snack}</option>) }
    </select>
  )
}

四、组件渲染可以看成手翻书

React 的工作过程就像播放手翻书动画。每调用一次组件函数,组件就返回手翻书的一页,调用多次,装订起来,快速一翻就形成了完整的交互界面。

代码演示

function App() {
  console.log("新一帧") // 加了这一句方便跟踪程序运行状况
  const [isDialogVisible, setIsDialogVisible] = React.useState(false)
  const dialog = (
    <div style={styles.dialogBackdrop}>
      <div style={styles.dialogContainer}>
        <div>消息对话框</div>
        <button onClick={() => { setIsDialogVisible(false) }}>关闭</button>
      </div>
    </div>
  );
  return (
    <div style={styles.app}>
      <div>观察者窗口主控界面</div>
      <button onClick={() => { setIsDialogVisible(true) }}>打开消息对话框</button>
      { isDialogVisible && dialog }
    </div>
  );
}

 如果用户点击打开消息对话框一次,并点击关闭,JavaScript 控制台上会出现几行 新一帧

三行

第一行:APP首次渲染

第二行:点击打开消息对话框后再次渲染

第三行:点击关闭后再次渲染

五、react数据的不可变特性   

State 内的数据、Prop 和 React 元素都是不可变的 

 例如我们尝试修改和添加元素:

const [snacks, setSnacks] = useState([])
//添加新元素
snacks.push('芒果干')
//修改元素
snacks[5] = '巧克力'
//调用设置器
setSnacks(snacks)

上述修改是不起作用的,React 只要看到还是同一个数组,就会认为 State  中的数据没有发生任何变化。

正确方法是准备一个新数组:

// 添加新元素
const newSnacks = [...snacks, '芒果干']
setSnacks(newSnacks)

// 替换 index 为 4 的元素
const newSnacks2 = [...snacks.slice(0, 4), '巧克力', ...snacks.slice(5)]
setSnacks(newSnacks2)

不可变特性同样也适用于对象、字符串和其他数据类型

为什么要不可变?

就单次操作来说,重建确实比直接修改慢,但是,从总体上来说,这种采用重建来修改状态的机制性能更优

在绝大多数的用户界面里,发生最普遍频繁的,不是对程序状态的修改,而是对状态数据的读取比对。如果我们约定所有的状态数据值都是不可变的,那么对其的比对操作的性能上就会有至少一个数量级的提升

相反,如果数据结构是不可变的,判断起来就容易很多:只需要做一个“浅层比较”,看看是不是同一个数组或对象就行了(下图)

所以,在最开始的例子里,即使我们替换了数组 snacks 内的元素、并调用 setSnacks(snacks),由于 snacks 是同一个数组,React 会认为 State 并未发生改变,从而置之不理。

React 的适用场景:如果整个界面和程序状态大致不变、而需要非常频繁地读取比对系统状态

第三方库immer

背景:

我们通常使用展开操作符 ... 来复制并修改数组或对象,这种方法在数据结构简单时还算方便好用,然而有多层嵌套的对象或数组时,就会显得累赘

作用:

immer 会为我们生成一个新的实例,并保证它符合不可变约定,只需要set修改后的数据即可

使用方法:

npm install -S immer
import produce from 'immer'
...
function App() {
  const [todos, setTodos] = useState({...})
  ...
  setTodos(produce(draft => {
    draft[1].status.isComplete = true
}))
  ...
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/904589.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MoveIt 控制自己的真实机械臂【2】——编写 action server 端代码

完成了 MoveIt 这边 action client 的基本配置&#xff0c;MoveIt 理论上可以将规划好的 trajectory 以 action 的形式发布出来了&#xff0c;浅浅尝试一下&#xff0c;在 terminal 中运行 roslaunch xmate7_moveit_config_new demo.launch 报错提示他在等待 xmate_arm_control…

jenkins部署手册

文章目录 一、环境配置资源配置操作系统资源配置服务器 二、jenkins软件部署2.1 下载软件包2.2 启动jenkins2.2.1 准备jdk环境2.2.2 准备maven环境2.2.3 编写jenkins.service 2.3 配置jenkins2.3.1 修改插件源&#xff08;非必要不修改&#xff09;2.3.2 配置环境变量2.3.3 配置…

网络编程 UDP编程 Linux环境 C语言实现

UDP编程 1. 一般UDP编程 UDP传输特点&#xff1a;非面向连接、不可靠的、无序的 报式传输 支持组播和广播 UDP应用数据最大长度建议&#xff1a;MTU(以太网分组数据的最大长度)1500 - 20(IP头) - 8(UDP头) 1472Bytes 客户端&#xff1a;支持两种形式的代码编写: 1. 不定向…

【Python爬虫实战】深入理解Python异步编程:从协程基础到高效爬虫实现

#1024程序员节&#xff5c;征文# &#x1f308;个人主页&#xff1a;易辰君-CSDN博客 &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/2401_86688088/category_12797772.html ​ 目录 前言 一、异步 &#xff08;一&#xff09;核心概念 &#xff08;二&#xff09;…

Flutter InkWell组件去掉灰色遮罩

当InkerWell组件内部获取到焦点时&#xff0c;会展示一层灰色遮罩 将focusColor属性设置为透明即可 Flutter InkWell焦点效果源码分析 问题描述 当 InkWell 组件获得焦点时&#xff0c;会显示一层灰色遮罩效果。需要找出这个效果是由哪些组件控制的&#xff0c;以及具体的…

每天一题:洛谷P2041分裂游戏

题目描述 有一个无限大的棋盘&#xff0c;棋盘左下角有一个大小为 n 的阶梯形区域&#xff0c;其中最左下角的那个格子里有一枚棋子。你每次可以把一枚棋子“分裂”成两枚棋子&#xff0c;分别放在原位置的上边一格和右边一格。&#xff08;但如果目标位置已有棋子&#xff0c…

频率限制:WAF保护网站免受恶意攻击的关键功能

频率限制&#xff08;Rate Limiting&#xff09;是一项有效的安全措施&#xff0c;用于控制每个 IP 地址的访问速率&#xff0c;以防止恶意用户利用大量请求对网站进行攻击&#xff0c;例如防止 CC 攻击等。频率限制不仅能保护网站资源&#xff0c;还能提升服务的稳定性。 下面…

植物源UDP-糖基转移酶及其分子改造-文献精读75

植物源UDP-糖基转移酶及其分子改造 摘要 糖基化能够增加化合物的结构多样性,有效改善水溶性、药理活性和生物利用度,对植物天然产物的药物开发至关重要。UDP-糖基转移酶(UGTs)能够催化糖基从活化的核苷酸糖供体转移到受体形成糖苷键,植物中天然产物的糖基化修饰主要通过UGTs实…

搜维尔科技:Xsens动作捕捉、Manus数据手套和Faceware面部捕捉技术集成,应用于元宇宙数字人制作解决方案

Xsens动作捕捉、Manus数据手套和Faceware面部捕捉技术集成&#xff0c;能够实现非常逼真且高效的数字人动作和表情捕捉&#xff01; 硬件连接与数据传输方面&#xff1a; 1.Xsens与Manus的集成&#xff1a;Xsens惯性动作捕捉系统通常可以与Manus的数据手套直接集成。Xsens主要…

基于SpringBoot的汽车票网上预订系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

块设备驱动的基本概念

块设备与字符设备 块设备只能以块为单位接收输入和返回输出&#xff0c;而字符设备则以字节为单位。大多数设备是字符设备&#xff0c;因为它们不需要缓冲而且不以固定块大小进行操作&#xff1b;字符设备只能被顺序读写&#xff0c;而块设备可以随机访问。 块设备对于I/O请求…

python 使用进程池并发执行 SQL 语句

这段代码使用了 Python 的 multiprocessing 模块来实现真正的并行处理&#xff0c;绕过 Python 的全局解释器锁&#xff08;GIL&#xff09;限制&#xff0c;从而在多核 CPU 上并发执行多个 SQL 语句。 from pyhive import hive import multiprocessing# 建立连接 conn hive.…

Ajax:请求 响应

Ajax&#xff1a;请求 & 响应 AjaxjQuery的Ajax接口$.get$.post$.ajax PostMan 接口测试getpost Ajax 浏览器中看到的数据&#xff0c;并不是保存在浏览器本地的&#xff0c;而是实时向服务器进行请求的。当服务器接收到请求&#xff0c;就会发回一个响应&#xff0c;此时浏…

ALIGN_ Tuning Multi-mode Token-level Prompt Alignment across Modalities

文章汇总 当前的问题 目前的工作集中于单模提示发现&#xff0c;即一种模态只有一个提示&#xff0c;这可能不足以代表一个类[17]。这个问题在多模态提示学习中更为严重&#xff0c;因为视觉和文本概念及其对齐都需要推断。此外&#xff0c;仅用全局特征来表示图像和标记是不…

Linux-计算机网络-epoll的LT,ET模式

一.epoll的LT和ET模式介绍 epol 对文件描述符有两种操作模式:LT(Level Trigger&#xff0c;电平触发)模式和 ET(EdgeTrigger&#xff0c;边沿触发)模式。LT模式是默认的工作模式。当往epol 内核事件表中注册一个文件描述符上的 EPOLLET 事件时&#xff0c;epoll将以高效的 ET …

新160个crackme - 087-d4ph1-crackme2

运行分析 需破解Name和Serial PE分析 ASM程序&#xff0c;32位&#xff0c;无壳 静态分析&动态调试 ida找到关键字符串 INT_PTR __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4) {HICON IconA; // eaxint v5; // ediunsigned int v6; // ebxchar v7; // a…

leetcode 303.区域和检索-数组不可变

1.题目要求: 2.题目代码: class NumArray { public:vector<int> array;NumArray(vector<int>& nums) {array nums;}int sumRange(int left, int right) {int sum 0;while(left < right){sum array[left];left;}return sum;} };/*** Your NumArray obje…

【SVM手把手推导】对偶问题应用之支持向量机SVM(Hard Margin)

1. 对偶问题应用之支持向量机SVM 1.1 SVM 设给定数据集&#xff1a; { ( s i , y i ) : y i ∈ { 1 , − 1 } , i 1 , ⋯ , m } \{(\mathbf{s}^i,y^i):y^i\in\{1,-1\},i1,\cdots,m\} {(si,yi):yi∈{1,−1},i1,⋯,m}&#xff0c;我们想要找到一个决策超平面&#xff08;decis…

大数据技术的前景如何?

在当今数字化迅猛发展的时代&#xff0c;大数据技术的前景显得尤为广阔。随着数据量的激增&#xff0c;如何有效利用这些数据成为了各行各业关注的焦点。未来五年&#xff0c;大数据技术的发展趋势可以从市场规模、技术融合、行业应用和政策支持等多个方面进行深入分析。 1. 市…

【STM32】单片机ADC原理详解及应用编程

本篇文章主要详细讲述单片机的ADC原理和编程应用&#xff0c;希望我的分享对你有所帮助&#xff01; 目录 一、STM32ADC概述 1、ADC&#xff08;Analog-to-Digital Converter&#xff0c;模数转换器&#xff09; 2、STM32工作原理 二、STM32ADC编程实战 &#xff08;一&am…