什么是react

react18就是react的18版本,是一个用于构建用户界面的js库,说它是框架也行(router redux )react主要用于构建UI(就是写页面的)

mvc三层架构

m就是model模型:用来管数据的

c就是controller:控制器层也叫逻辑层

v就是view:视图层渲染数据的

以下是他们三者之间的关系

创建react

先下载插件

选择这个

使用全局脚手架创建

pnpx create-react-app react-demo

启动项目

cd

react-demo

#

进入项目根目录

yarn

start

#

启动 在package。json里找

jsx语法的基本概念

React

使用

JSX

来替代常规的

JavaScript

JSX

是按照

XML

语法规范 的

JavaScript

语法扩展。

JSX

语法的本质:

并不是直接把

JSX

渲染到页面上,而是内部先转换成了

createElement

形式,再 渲染的。

JSX

JavaScript

语法扩展,可以让你在

JavaScript

文件中书写类似

HTML

的标签。虽然还有其它

方式可以编写组件,但大部分

React

开发者更喜欢

JSX

的简洁性,并且在大部分代码库中使用它。

JSX

的优点

JSX

执行更快,因为它在编译为

JavaScript

代码后进行了优化;

它是类型安全的,在编译过程中就能发现错误;

使用

JSX

编写模板更加简单快速。

在这里送大家一个面试题

JSX

语法基础

JSX

注释:推荐使用

{/*

这是注释

*/}

JSX

中添加

class

类名:需要使用

className

来替代

class

htmlFor

替代

label

for

属性;

JSX

创建

DOM

的时候,所有节点必须有唯一的根元素进行包裹;

JSX

语法中,标签必须成对出现,如果是单标签,则必须自闭合;

JSX

语法中,渲染动态数据的地方使用一对

{

表达式

}

进行渲染

jsx的应用

如果嵌套的变量是字符串、数值类型,

JSX

会把它们当作文本进行渲染。(

v-text

如果嵌套的变量是

undefined

null

、布尔值,

JSX

会忽略掉它们。

如果嵌套的变量是数组,

JSX

会把它们当作列表进行渲染(要加

key

)。(

v-for

如果嵌套的表达式是函数调用,这个函数的返回值必须是

JSX

支持的变量类型。

如果嵌套的变量是对象,在动态

style

等特殊语法环境下,是支持的。

JSX

元素的属性是动态变量时,也要用

{}

包起来。(

v-bind

JSX

语法中有三个不一样的属性

className

(相当于

html

class

属性)

htmlFor

(相当于

html

中的

for

属性)

tabIndex

(相当于

html

中的

tabindex

属性)

 JSX

语法中新增了三个属性

key

渲染一个列表时,或者渲染一个数组时,都要加

key

,为了让

“diff

运算

更加高效。

ref

用于快速地访问

DOM

对象或者访问

JSX

实例对象。

dangerouslySetInnerHTML

JSX

节点中插入一段可以参与渲染的

HTML

字符串(相当于

Vue

中的

v

html

jsx注意点

JSX

元素必须要用一个

tag

包裹起来

送大家的面试题

 为什么操作dom特别消耗性能 虚拟dom为什么性能更高?

答:因为dom操作时对标签的300多哥属性进行操作而react的虚拟dom只有不到10哥属性 每一次数据的操作都是要消耗内存的 所以说虚拟dom的性能更高

jsx是不可变对象

什么是不可变对象?

不可变对象指的是一旦创建后,就无法再被修改的对象。在 JavaScript 中,字符串和原始值(如数字、布尔值)是不可变的。这意味着一旦创建了字符串或原始值,你就不能更改它们的值。

为什么不可变性在 React 中非常重要?

在 React 中,不可变性非常重要,因为它能够帮助我们避免出现一些常见的 Bug,并且使得组件的状态管理更加可控。

方便比较:在 React 中,使用不可变对象可以方便地进行性能优化。React 可以轻松地对新旧对象进行比较,从而确定是否需要重新渲染组件。 可预测性:不可变性能够让你更容易追踪数据的变化。当你修改一个不可变对象时,你实际上是创建了一个全新的对象,而不是改变原有对象,这样就可以更容易地推断数据的变化。 纯组件与性能提升:React 中的 PureComponent 和 shouldComponentUpdate 都依赖于不可变性来决定是否需要重新渲染组件。如果组件的状态是不可变的,React 就可以更容易地进行优化和避免不必要的重新渲染。

JS 中的不可变对象

在 JavaScript 中,虽然定义一个变量后不能改变其指向的内存地址,但你可以通过使用不可变性的方式来改变对象本身。例如,你可以使用 ES6 的扩展运算符或者 Object.assign() 方法来创建新的对象,而不是直接修改现有对象。  

React 中的不可变对象

在 React 中,通常会使用 immutability-helper 库或者简单地使用展开运算符(spread operator)来创建新的状态对象,而不是直接修改现有的状态。这种做法确保了 React 组件状态的不可变性,从而更容易追踪状态的变化并且可以提高性能。

事件处理

添加事件

React

元素的事件处理和

DOM

元素的很相似,但是有一点语法上的不同:

React

事件的命名采用小驼峰式(

camelCase

),而不是纯小写。

使用

JSX

语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

React的状态定义及修改【重点】

useState

是一个

Hook

函数,让你在函数组件中拥有

state

变量。它接收一个初始化的

state

,返回是一

个数组,数组里有两个元素,第一个元素是当前状态值和另一个更新该值的方法。

这儿有一些需要记住的关键的点:

修改方法不会立即更新值

如果你需要用到之前的值更新状态,你必须将之前的值传递给该方法,则它会返回一个更新后的

值,

eg:

setMessage(previousVal => previousVal + currentVal)

如果你使用同样的值作为当前状态,则

React

不会触发重新渲染。(

React

是用

Object.is

来做比较

的)

useState

不像类组件中的

this.setState

合并对象,它是直接替换对象

useState使用规则

在 React 中使用 useState 钩子有一些基本的规则和最佳实践:

1. 在函数式组件中使用

useState 应该仅在函数式组件或自定义钩子中被调用。它不能在 class 组件中使用。

2. 返回值

useState 返回一个状态变量和一个更新该状态的函数,通常以数组的形式返回。第一个元素是当前状态的值,第二个元素是更新状态的函数。

3. 初始化状态

useState 的初始参数用于定义状态的初始值,并且只会在组件的初始渲染期间起作用。

4. 多个状态变量

你可以多次调用 useState 来定义多个不同的状态变量。

5. 更新状态

调用由 useState 返回的更新函数来更改状态的值。这个更新函数可以接受一个新的状态值,也可以接受一个函数,以便根据先前的状态进行计算。

6. 函数式更新

如果新状态取决于先前的状态,推荐使用函数式更新,而不是直接传入新的值给更新函数。这样可以避免因为闭包导致的问题。

总结

useState 是 React 中非常强大且灵活的状态管理工具。通过遵循这些规则和最佳实践,你可以更好地利用 useState 来管理组件的状态,从而使得组件更加可控和可维护。

react-hooks

全家桶

类组件和函数组件的区别

类组件和函数组件的区别:   类组件有完整的生命周期 含事故组件没有(函数组件移入hooks后可以具备生命周期) 类组件需要继承class 函数组件不需要 类组件可以获取实例化的this函数组件没有实例this

react hooks

useEffect

useEffect 是 React Hooks 中最常用的一个,它允许在函数式组件中执行副作用操作。这些副作用可以包括数据获取、订阅或手动操作 DOM 等。

副作用的种类

数据订阅和更新状态:可以通过 useEffect 来订阅外部数据源,并在数据发生变化时更新组件的状态。 DOM 操作:可以使用 useEffect 来进行 DOM 操作,比如设置标题、管理焦点、添加事件监听器等。 网络请求:可以在 useEffect 中进行网络请求,并根据返回结果更新组件状态。 清理操作:可以通过 useEffect 返回一个清理函数,用来清理副作用,比如取消订阅、清除定时器等。

注意事项

第二个参数的作用:如果提供了依赖数组,React 将会在组件卸载或依赖发生变化时,清理之前的副作用操作,并重新运行副作用函数。如果没有提供依赖数组,副作用函数将在每次渲染后都执行。 异步操作:useEffect 中的操作是异步执行的,因此不会阻塞浏览器渲染。 多个 useEffect:你可以在单个组件中多次使用 useEffect 来分离不同的逻辑。 清理副作用:如果需要进行清理操作,可以在 useEffect 的回调函数中返回一个清理函数

小结

如果你要使用此优化方式,请确保数组中包含了所有外部作用域中会随时间变化并且在

effect

中使

用的变量,否则你的代码会引用到先前渲染中的旧变量。

如果想执行只运行一次的

effect

(仅在组件挂载和卸载时执行),可以传递一个空数组(

[]

)作为

第二个参数。这就告诉

React

你的

effect

不依赖于

props

state

中的任何值,所以它永远都不需

要重复执行。这并不属于特殊情况

——

它依然遵循依赖数组的工作方式。

如果你传入了一个空数组(

[]

),

effect

内部的

props

state

就会一直拥有其初始值。尽管传入

[]

作为第二个参数更接近大家更熟悉的

componentDidMount

componentWillUnmount

思维模

式,但我们有更好的方式来避免过于频繁的重复调用

effect

。除此之外,请记得

React

会等待浏览

器完成画面渲染之后才会延迟调用

useEffect

,因此会使得额外操作很方便。

 

useRef

useRef 是 React 中的一个 Hook,它提供了一种在函数式组件中创建可变值的方式。这些可变值可以包括对 DOM 元素的引用以及其他任意可变的数据。useRef 返回的对象在组件渲染之间保持不变,并且不会引起组件重新渲染。

实际上,useRef 并不仅仅用于访问 DOM 元素,它还可以用来存储任何可变值,而且修改 ref 的 current 属性并不会触发组件重新渲染。这使得 useRef 成为一种非常有用的工具,可以方便地操作 DOM、保存组件内部状态和缓存数据,同时避免不必要的重新渲染。

我门为什么要用useRef

因为在

hooks

中,我们所声明的所有变量是只属于它的闭包,所以,我们无法做到变量的一个共享。

然后不可变的

state

并不适合我们存储一些不参与

UI

显示的变量

(state

不适合用来存储一些不参与

UI

变量,普通变量会在每次

render

时重置

)

好在

hooks

为我们提供了

useRef

去存储可变且不参与

UI

显示的变量,并且可以在每一轮

render

中共

享。

useRef

不仅可以用来存储对

Dom

元素的引用(它的本意),更可以用来存储我们需要在每轮

render

中共享且可变的变量。

所以通过

useRef

我们可以解决很多需要变量共享的问题。

useRef 主要用于两个主要方面:

持久性存储: 当你需要在函数组件的多次渲染之间存储数据,并且希望该数据在重新渲染时保持不变时,可以使用 useRef。 DOM 元素引用: 如果你需要访问或操作 DOM 元素而不想通过 React state 进行管理,useRef 可以帮助你获取对 DOM 节点的引

memo

useMemo

useCallback

他们是用于避免Hooks重复渲染的,他们三需要组合并结合场景使用

这是我们的例子:

在memo的文件夹里创建三个jsx

useMemo

useCallback不要滥用 本身会产生额外的开销 并且两个方法要和memo搭配使用

immutable.js不可变数据(了解一下就好)

当我们说数据是“不可变”的时候,意味着一旦创建了数据,就无法再对它进行改变。Immutable.js 是一个帮助 JavaScript 开发者处理这种不可变数据的工具库。

为什么要使用不可变数据?因为它可以避免出现意外的数据修改,从而让代码更加可靠、易于理解和维护。在 React 或其他框架中,使用不可变数据还有助于提高性能,因为它们可以更轻松地检测到数据的变化。

Immutable.js 提供了一些特殊的数据结构,比如 List(列表)、Map(映射)、Set(集合)等。这些数据结构可以让你以一种安全的方式来操作数据,因为任何修改数据的方法都会返回一个新的数据对象,而不是直接改变原始数据。这样做可以确保我们对数据的每次修改都是可控的,并且不会对其他部分的代码造成影响。

immutable.js中的API的使用、

map

map 方法用于对 Immutable 集合(比如 List 或 Map)中的每个元素执行相同的操作,并返回一个新的集合。它类似于 JavaScript 中数组的 map 方法。

 is()

is 方法用于比较两个 Immutable 对象是否相等。由于 Immutable 数据的特性,直接使用 === 运算符进行比较可能会导致意外的结果。is 方法能够正确地比较两个 Immutable 对象的值,而不仅仅是引用。

toJS()

toJS 方法用于将 Immutable 数据结构转换为 JavaScript 原生的数据结构。这在需要将 Immutable 数据传递给不能处理 Immutable 数据的函数或组件时非常有用。

 fromJS()

fromJS 方法用于将 JavaScript 原生的数据结构转换为 Immutable 数据结构。这在需要将普通 JavaScript 数据转换为 Immutable 数据时非常有用。

这些方法在处理 Immutable 数据时非常有用,可以帮助你更加灵活地操作不可变数据并进行比较。使用这些方法可以确保你在处理不可变数据时遵循最佳实践,并且更容易地将 Immutable 数据与其他部分的代码集成在一起。

js中的Immutable Data

在 JavaScript 中,Immutable Data 意味着一旦数据被创建,它就无法被直接修改。相反,任何对数据的修改都会产生一个新的数据对象。这种编程风格可以帮助避免因为直接修改数据而引起的意外后果,并且有助于更好地管理状态和数据。

虽然 JavaScript 本身不是一种纯粹的不可变语言,但你可以通过采用特定的编程实践来达到不可变数据的效果。这包括使用 Object.assign、Spread 运算符或者数组的 map 等方法来创建新的对象和数组,而不是直接修改原始数据。

另外,像 Immutable.js 或者其他类似的库也可以帮助你更轻松地处理不可变数据。这些库提供了一系列的持久化数据结构以及操作这些数据结构的方法,使得在 JavaScript 中处理不可变数据变得更加简单和高效

自定义hok

自定义 Hook 是 React 中的一个强大特性,它允许你抽象出组件中的逻辑,使得这些逻辑可以在不同组件中被重用。以下是自定义 Hook 的一些认识和特点:

认识和特点:

逻辑封装:自定义 Hook 允许你将组件中的逻辑抽象到可重用的函数中。这样做有助于将应用程序的逻辑进行分离,并使得代码更易于维护。 命名规范:React 要求自定义 Hook 的名称必须以"use"开头,以便能够正确识别它们。比如 useCustomHookName。 包含其他 Hook:自定义 Hook 可以包含内置的 Hook(比如 useState、useEffect)以及其他自定义 Hook。这使得你能够构建具有复杂功能的自定义 Hook。 复用性:自定义 Hook 提供了一种有效的方式来在不同的组件中复用组件逻辑。这有助于减少重复的代码,并且提高了代码的可维护性。 业务逻辑分离:使用自定义 Hook 有助于将业务逻辑与组件本身分离开来。这使得组件更易于理解和测试。 状态管理:自定义 Hook 可用于封装特定的状态管理逻辑,例如数据获取、表单处理等。

创建自定义 Hook:

编写函数:首先,在你的项目中创建一个函数,以"use"开头命名,这是 React 的约定。比如 useCustomFetch。在这个函数里,你可以使用任意 React 内置 Hook 以及其他自定义 Hook。

封装逻辑:在自定义 Hook 中,你可以定义任何你需要的逻辑。在这个例子中,我们使用 useState 来管理数据和加载状态,使用 useEffect 发起网络请求,并最终返回获取到的数据和加载状态。 返回值:确保自定义 Hook 返回一些值,通常是一个对象、数组或其他需要在组件中使用的值。在这个例子中,我们返回了包含数据和加载状态的对象 在函数组件中使用自定义 Hook: 导入自定义 Hook:在你想要使用自定义 Hook 的函数式组件中,导入你之前创建的自定义 Hook调用并使用:在组件中,使用自定义 Hook 时只需调用它,并将其返回的值用于渲染逻辑或其他操作。在上面的例子中,我们调用 useCustomFetch 并使用从中获取的数据和加载状态来进行条件渲染

Hook的规则

只能在函数组件中使用:Hook 只能在 React 函数组件中被调用。不能在普通的 JavaScript 函数中使用 Hook。 在顶层调用 Hook:确保 Hook 在你的 React 函数的顶层调用。不要在循环、条件语句或嵌套函数中调用 Hook。 按照相同的顺序调用 Hook:React 依靠 Hook 调用的顺序来确定每个状态对应的含义。因此,在组件的每次渲染中,Hook 的调用顺序必须保持一致。 以"use"开头命名:自定义 Hook 的名称必须以"use"开头,以便能够正确识别它们。比如 useCustomHookName

      实用hooks

useState:useState Hook 用于在函数式组件中添加内部状态。它返回一个包含当前状态和更新状态的函数的数组。你可以使用它来添加组件所需的内部状态,而无需创建类组件。 useEffect:useEffect Hook 用于在函数式组件中执行副作用操作。副作用操作可能包括数据获取、订阅外部事件、手动修改 DOM 等。它接受一个函数作为参数,这个函数会在每次渲染时都执行。你也可以选择传递第二个参数,表示仅当依赖项列表中的值发生变化时才执行该效果。 useContext:useContext Hook 用于在函数式组件中访问 React 上下文。通过调用 useContext 并传入上下文对象,你可以轻松地访问全局的上下文数据或方法,而无需在组件树中一级级传递 props。 useReducer:useReducer Hook 用于在函数式组件中管理复杂的状态逻辑。它类似于 Redux 中的 reducer,可以帮助你更好地处理需要多个状态相互影响的场景。 useCallback:useCallback Hook 用于在函数式组件中缓存回调函数,以便避免不必要的重新渲染。这对于将回调函数传递给子组件并且依赖于引用相等性的情况非常有用。 useMemo:useMemo Hook 用于在函数式组件中缓存计算值,以便在渲染时避免重复计算。这对于性能优化和避免不必要的计算开销很有帮助。 useRef:useRef Hook 用于在函数式组件中创建可变的引用。它返回一个持久化的对象,在整个组件的生命周期中保持不变。这对于保存 DOM 节点、保存其他任意的可变值或者追踪组件内部的引用变量非常有用。

hooks闭包陷阱

什么是闭包??

闭包就是当一个外部函数包裹着一个内部函数,并且这个外部函数还是这个内部函数的返回值,就形成了闭包

2.闭包可以延长变量的生命周期 闭包里的变量会常驻内存 所以要谨慎使用 不要滥用闭包 容易造成内存泄漏。 3. 在react hooks中 所有的hooks都是闭包 所以很容易出现一种情况   在代码中拿到的闭包的数据是过期的也可以说不是最新的这个被称为闭包陷阱 4. 在技术中没有私有变量 es6之前没有块级作用域 所以项目中很容易出现变量污染问题   5.可以通过让闭包私有化 形成一个独立的函数作用域 最典型的闭包就是IIFE立即执行函数 es6块级作用域出来后闭包的使用场景就变少了

什么是闭包陷阱呢?

闭包陷阱是指在 JavaScript 中,由于闭包的特性导致的一些意外问题。闭包是指函数可以访问其外部作用域中的变量,即使函数是在外部作用域执行之后定义的。这种特性使得在处理变量和函数作用域时需要谨慎,否则可能会导致一些意想不到的问题。

以下是一些常见的闭包陷阱:

循环中的闭包问题:当在循环中创建闭包时,通常会出现问题。例如,在 for 循环中创建了多个闭包来处理异步操作,但它们都引用了同一个循环变量。在循环结束后,闭包中引用的变量可能不是预期的值,因为它们共享相同的作用域链。 内存泄漏:如果没有正确地管理闭包中引用的变量,可能会导致内存泄漏。因为闭包会持有对外部作用域的引用,如果大量闭包一直存在且不被释放,可能会导致内存占用过高。 变量意外共享:由于闭包可以访问外部作用域的变量,有时会导致意外共享变量。这可能会导致在不同的闭包中修改同一个变量而产生意外的结果。 事件监听器中的闭包:在事件监听器中使用闭包时,引发的问题可能和循环中的闭包问题类似。如果在事件监听器内部创建了闭包来处理事件,并且这些闭包引用了外部作用域的变量,可能会导致意外的行为

useState

陷阱

陷阱代码

点击添加按钮,发现值更新了,打印的值却还是上次的

useState

修改状态 是异步执行无法获取更新后的值

解决方法:

所以我们不能修改后,把值拿去其他操作

(

应该拿

count+1)

可以通过

useRef

获取最新值

useEffect

陷阱

陷阱(过期闭包)

页面上

count

一直显示

1

useEffect

的第二个参数为空数组,所以只会在组件加载后仅执行一次,我们知道组件每次

render

时候都会生成一个新的

state

对象,对应一个快照,上述代码中,因为

useEffect

只执行了一次,所

以定时器中的

count

一直是最初快照里的

count

,那么页面中

count

的显示肯定不会改变

闭包陷阱产生的原因就是

useEffect

的函数里引用了某个

state

,形成了闭包(也有叫过时的闭包)

2.

解决方法

useEffect

第二个参数添加依赖项

count

并且每次更新,添加计时器,清除计时器

useCallback

陷阱

陷阱(获取父组件不是最新的)

useCallback

本来拿来优化性能,当依赖变化不用重新注册该函数

使用不当也会,出现一定的问题

1.

陷阱:【获取父组件的值,不是最新】

此时我们在 父组件点击 增加按钮

子组件的

count

发生改变 ,我们在点击打印按钮,发现

count

一直是

0

说明

useCallback

依赖为

[]

数组,取到

count

已经过期了

2.

解决方法

useCallback

第二个参数添加依赖的数据,依赖变化了函数会重新生成

希望这个简短总结能够帮助你对 React 有一个清晰的认识。React 的灵活性、性能和丰富的生态系统使其成为众多开发者青睐的前端库之一。无论是构建小型项目还是复杂的应用程序,React 都能提供强大的支持。祝你在使用 React 进行前端开发时取得成功!

精彩内容

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。