1、什么是React?
用于构建用户界面的 JavaScript 库,提供了 UI 层面的解决方案,遵循组件设计模式、声明式编程范式和函数式编程概念,以使前端应用程序更高效,使用虚拟DOM来有效地操作DOM,遵循从高阶组件到低阶组件的单向数据流,帮助我们将界面成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,构成整体页面.
2、React有什么特点?
1.它使用虚拟DOM 而不是真正的DOM。
2.它可以进行服务器端渲染。
3.它遵循单向数据流或数据绑定。
4.JSX语法
5.声明式编程
6.Component(组件化)
3、列出React的一些主要优点。
1、组件式开发,提高代码复用率
2、可以方便地在客户端和服务器端使用
3、由于 JSX,代码的可读性很好
4、React 很容易与 Meteor,Angular 等其他框架集成
5、使用React,编写UI测试用例变得非常容易
6、单向响应的数据流会比双向绑定的更安全,速度更快
4、React有哪些限制?
1、React 只是一个库,而不是一个完整的框架
2、它的库非常庞大,需要时间来理解
3、新手程序员可能很难理解
4、编码变得复杂,因为它使用内联模板和 JSX
5、什么是JSX?
JSX 是JavaScript XML 的简写。是 React 使用的一种文件,它利用 JavaScript 的表现力和类似 HTML 的模板语法。这使得 HTML 文件非常容易理解。此文件能使应用非常可靠,并能够提高其性能(说白了就是可以在 js 中写 html)。
6、为什么浏览器无法读取JSX?
浏览器只能处理 JavaScript 对象,而不能读取常规 JavaScript 对象中的 JSX。所以为了使浏览器能够读取 JSX,首先,需要用像 Babel 这样的 JSX 转换器将 JSX 文件转换为 JavaScript 对象,然后再将其传给浏览器。
7、React中的组件是什么?
组件是React应用的构建块。它们是独立且可重用的代码片段,用于定义UI的一部分。组件可以是类组件或函数组件,并且可以维护自己的状态和生命周期。
8、怎样解释 React 中 render() 的目的。
每个React组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的表示。如果需要渲染多个 HTML 元素,则必须将它们组合在一个封闭标记内,例如 <form>、<group>、<div> 等。此函数必须保持纯净,即必须每次调用时都返回相同的结果。
9、什么是 Props?
Props 是 React 中属性的简写。它们是只读组件,必须保持纯,即不可变。它们总是在整个应用中从父组件传递到子组件。子组件永远不能将 prop 送回父组件。这有助于维护单向数据流,通常用于呈现动态生成的数据。
10、React中的状态是什么?它是如何使用的?
状态是 React 组件的核心,是数据的来源,必须尽可能简单。基本上状态是确定组件呈现和行为的对象。与props 不同,它们是可变的,并创建动态和交互式组件。可以通过 this.state() 访问它们。
11、 React 中的箭头函数是什么?使用箭头函数的好处?
箭头函数(=>)是用于编写函数表达式的简短语法。这些函数允许正确绑定组件的上下文,因为在 ES6 中默认下不能使用自动绑定。使用高阶函数时,箭头函数非常有用。
好处:
(1)语法简洁:箭头函数的语法比传统的函数声明或函数表达式更简洁。
(2)不绑定 this:箭头函数不会创建自己的 this 值。在箭头函数内部,this 与封闭 词法环境的 this 值相同。这解决了在事件处理器和回调函数中使用 this 的问题。
(3)不绑定 arguments:箭头函数不会创建自己的 arguments 对象。它会从封闭 的词法环境中获取 arguments。
(4)不可以当作构造函数:箭头函数不能用作构造函数,不能使用 new 关键字。没有 prototype 属性:由于箭头函数不能用作构造函数,所以它也没有 prototype 属性。
(5)不支持 yield 关键字:箭头函数不能用作生成器函数。总的来说,箭头函数提供了一种更简洁、更方便的函数语法,特别适合用于那些需要匿名函数的场景。
12、什么是高阶组件(HOC)?
高阶组件是重用组件逻辑的高级方法,是一种源于 React 的组件模式。HOC 是自定义组件,在它之内包含另一个组件。它们可以接受子组件提供的任何动态,但不会修改或复制其输入组件中的任何行为。你可以认为 HOC 是“纯(Pure)”组件。
13、你能用HOC做什么?
1、代码重用,逻辑和引导抽象
2、渲染劫持
3、状态抽象和控制
4、Props 控制
14、什么是纯组件?
纯(Pure) 组件是可以编写的最简单、最快的组件。它们可以替换任何只有 render() 的组件。这些组件增强了代码的简单性和应用的性能。
15、React 中 key 的重要性是什么?
key 用于识别唯一的 Virtual DOM 元素及其驱动 UI 的相应数据。它们通过回收 DOM 中当前所有的元素来帮助 React 优化渲染。这些 key 必须是唯一的数字或字符串,列表元素需要一个唯一的key来帮助React识别哪些项已经改变、添加或删除。这提高了渲染列表的性能,尤其是在进行列表项的重新排序或操作时。
16、什么是React 路由?
React 路由是一个构建在 React 之上的强大的路由库,它有助于向应用程序添加新的屏幕和流。这使 URL 与网页上显示的数据保持同步。它负责维护标准化的结构和行为,并用于开发单页 Web 应用。React 路由有一个简单的API。
17、为什么 useState 返回的是数组而不是对象?
因为解构赋值的原因:
返回数组,可以对数组中的变量命名,代码看起来也比较干净。
返回对象,那就必须和返回的值同名,不能重复使用了。
18、如何实现 React 懒加载?
React 16.6 之后,React 提供了 React.lazy 方法来支持组件的懒加载。配合 webpack 的 code-splitting 特性,可以实现按需加载。
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
);
}
19、React VS Vue 有何区别
0、设计理念
React: 更倾向于函数式编程思想,推崇组件的不可变性和单向数据流。
Vue: 结合了响应式编程和模板系统,致力于简化开发过程。
1、组件化方式不同
React 组件包含状态和行为,所有组件共享一个状态树
Vue 每个组件都有自己的状态和行为,并且可以很容易将数据和行为绑定在一起
2、数据驱动方式不同
React 主要采用单向数据流,组件状态通过setState方法更新
Vue 支持双向数据绑定(使用v-model指令),适合于简化表单输入等场景。
3、模板语法不同
React 使用JSX(JavaScript XML),将标记语言与JavaScript逻辑混写。
Vue 使用基于HTML的模板语法,允许开发者使用纯HTML、CSS和JavaScript,支持指令
4、生命周期不同
React 生命周期:初始化、更新、卸载
Vue 生命周期:创建、挂载、更新、销毁
5、状态管理方式不同
React 状态管理通常通过使用Context API或引入如Redux、MobX的库来实现。
Vue 提供了Vuex作为官方的状态管理解决方案。
6、性能优化方式不同
React 性能优化:React.memo、shouldComponentUpdate
Vue 性能优化:keep-alive、v-if
7、响应式系统
React: 通过setState和useState等API显式地触发UI更新。
Vue: 通过其响应式系统自动追踪依赖并在数据变化时更新视图。
8、类型支持
React: 原生支持JavaScript,但可以很好地与TypeScript结合。
Vue: Vue 3提供了更好的TypeScript支持。
20、React 组件直接如何通信
父组件 => 子组件:
1、Props
2、ref
子组件 => 父组件:
1、回调函数
2、事件冒泡机制
3、使用 useImperativeHandle 和 forwardRef,另一种方法是使用React的useImperativeHandle Hook 和 forwardRef 高阶组件。
兄弟组件之间:
1、利用父组件通信
不相关的组件之间:
1、Context
2、全局变量
3、 观察者模式
4、Redux/mobx/dva等
21、什么是 useReducer
useReducer 是 React Hooks 中的一个函数,用于管理和更新组件的状态。它可以被视为 useState 的一种替代方案,适用于处理更复杂的状态逻辑。相比于 useState,useReducer 在处理复杂状态逻辑时更有优势,因为它允许我们将状态更新的逻辑封装在 reducer 函数中,并根据不同的动作类型执行相应的逻辑。这样可以使代码更具可读性和可维护性,并且更容易进行状态追踪和调试。
22、React类式组件和函数式组件的区别有哪些呢?
1、语法不同、设计思想不同
函数式组件是函数式编程思想,而类组件是面向对象编程思想。面向对象编程将属性和方法封装起来,屏蔽很多细节,不利于测试。
2、生命周期、状态变量
类式组件:使用state对象定义状态变量,有诸如componmentDidMount、shouldComponentUpdate等生命周期钩子函数;
函数式组件:没有this,使用一系列的内置hooks实现对应的功能,比如使用useState创建状态变量,使用useEffect实现类似于componmentDidMount、shouldComponentUpdate等生命周期钩子函数的功能。
3、复用性
类式组件:使用hoc(高阶组件)、render props实现组件的逻辑复用、拓展组件的功能。
函数式组件:使用自定义hooks实现组件的逻辑复用。注意:
避免在 循环/条件判断/嵌套函数 中调用 hooks,保证调用顺序的稳定;
不能在 useEffect 中使用 useState,React 会报错提示;
类组件不会被替换或废弃,不需要强制改造类组件,两种方式能并存
23、setState 是同步还是异步?
react 18 之前
在Promise的状态更新、js原生事件、setTimeout、setInterval..中是同步的。
在react的合成事件中,是异步的。
setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。
react 18 之后setState都会表现为异步(即批处理)。
24、 React 服务端渲染(SSR)原理?
1、node server 接收客户端请求,得到当前的请求 url 路径,然后在已有的路由表内查找到对应的组件,拿到需要请求的数据,将数据作为 props、context或者store 形式传入组件
2、然后基于 react 内置的服务端渲染方法 renderToString() 把组件渲染为 html 字符串在把最终的 html 进行输出前需要将数据注入到浏览器端
3、浏览器开始进行渲染和节点对比,然后执行完成组件内事件绑定和一些交互,浏览器重用了服务端输出的 html 节点,整个流程结束
25、常用的 React Hooks
状态钩子 (useState): 用于定义组件的 State,类似类定义中 this.state 的功能
useReducer:用于管理复杂状态逻辑的替代方案,类似于 Redux 的 reducer。
生命周期钩子 (useEffect): 类定义中有许多生命周期函数,而在 React Hooks 中也提供了一个相应的函数 (useEffect),这里可以看做- componentDidMount、componentDidUpdate和componentWillUnmount的结合。
useLayoutEffect:与 useEffect 类似,但在浏览器完成绘制之前同步执行。
useContext: 获取 context 对象,用于在组件树中获取和使用共享的上下文。
useCallback: 缓存回调函数,避免传入的回调每次都是新的函数实例而导致依赖组件重新渲染,具有性能优化的效果;
useMemo: 用于缓存传入的 props,避免依赖的组件每次都重新渲染;
useRef: 获取组件的真实节点;用于在函数组件之间保存可变的值,并且不会引发重新渲染。
useImperativeHandle:用于自定义暴露给父组件的实例值或方法。
useDebugValue:用于在开发者工具中显示自定义的钩子相关标签。
26、useEffect VS useLayoutEffect
useEffect 在 React 的渲染过程中是被异步调用的,用于绝大多数场景;useLayoutEffect 会在所有的 DOM 变更之后同步调用,主要用于处理 DOM 操作、调整样式、避免页面闪烁等问题。也正因为是同步处理,所以需要避免在 useLayoutEffect 做计算量较大的耗时任务从而造成阻塞。
useEffect 是按照顺序执行代码的,改变屏幕像素之后执行(先渲染,后改变DOM),当改变屏幕内容时可能会产生闪烁;useLayoutEffect 是改变屏幕像素之前就执行了(会推迟页面显示的事件,先改变DOM后渲染),不会产生闪烁。useLayoutEffect总是比useEffect先执行。
27、React中的state和props的区别
state是组件内部的状态,可以被组件自身管理和更改。
props(属性)是从父组件传递给子组件的数据,子组件不能修改接收到的props(单向数据流)。
相同点:
两者都是 JavaScript 对象
两者都是用于保存信息
props 和 state 都能触发渲染更新
区别:
props 是外部传递给组件的,而 state 是在组件内被组件自己管理的,一般在 constructor 中初始化
props 在组件内部是不可修改的,但 state 在组件内部可以进行修改
state 是多变的、可以修改
28、React中的虚拟DOM是什么
虚拟DOM是内存中的DOM表示。React使用虚拟DOM来优化DOM的更新过程。它通过比较新旧虚拟DOM的差异,并仅更新实际DOM中改变的部分,提高应用性能。
29、React 的生命周期方法有哪些 ?
1 componentWillMount:在渲染之前执行,用于根组件中的 App 级配置。
2 componentDidMount:在第一次渲染之后执行可以在这里做AJAX请求,DOM 的操作或状态更新以及设置事件监听器。
3 componentWillReceiveProps:在初始代render的时候不会执行,它会在组件接受到新的状态(Props)时被触发,一般用于业组件状态更新时子组件的重新渲染。
4 shouldComponentUpdate:确定是否更新组件。默认情况下,它返回true。如果确定在 state 或props 更新后组件不需要在重新渲染,则可以返回false,这是一个提高性能的方法。
5 componentWillUpdate:在shouldComponentUpdate返回 true 确定要更新组件之前执行。
6 componentDidUpdate:它主要用于更新DOM以响应props或state更改。
7 componentWillUnmount:它用于取消任何的网络请求,或删除与组件关联的所有事件监听器。
30、为什么使用 React Hooks
Hooks 通常支持提取和重用跨多个组件通用的有状态逻辑,而无需承担高阶组件或渲染 props 的负担。
Hooks 可以轻松地操作函数组件的状态,而不需要将它们转换为类组件。
避免使用生命周期方法。
31、父子组件的useEffec哪个先执行?
先执行子组件再执行父组件。react保证了每次运行useffect的同时,DOM都已经更新完毕。有一些场景,需要父组件的执行顺序在子组件前面,可以考虑一下使用useLayoutEffect
32、什么是 Virtual DOM
1、Virtual Dom,本质上是以 JavaScript 对象形式存在的对 DOM 的描述。创建虚拟DOM目的就是为了更好将虚拟的节点渲染到页面视图中,虚拟DOM对象的节点与真实DOM的属性一一照应
2、更新更快
3、无法直接更新 HTML
4、如果元素更新,则更新 JSX
5、DOM 操作非常简单
6、很少的内存消耗
33、Virtual DOM 工作过程有三个简单的步骤:
1、每当底层数据发生改变时,整个 UI 都将在 Virtual DOM 描述中重新渲染。
2、然后计算之前 DOM 表示与新表示的之间的差异。
3、完成计算后,将只用实际更改的内容更新 real DOM。
34、受控组件和非受控组件的区别
受控组件是React控制的组件,input等表单输入框值不存在于 DOM 中,而是以我们的组件状态存在。每当我们想要更新值时,我们就像以前一样调用setState。
不受控制组件是您的表单数据由 DOM 处理,而不是React 组件,Refs 用于获取其当前值;
35、React 18 有哪些更新
并发模式
更新 render API
自动批处理
Suspense 支持 SSR
startTransition
useTransition
useDeferredValue
useId
提供给第三方库的 Hook
36、React事件机制和原生DOM事件流有什么区别?
react中的事件是绑定到document上面的,
而原生的事件是绑定到dom上面的,
因此相对绑定的地方来说,dom上的事件要优先于document上的事件执行
37、Redux 工作原理
Redux 是 React 的第三方状态管理库,创建于上下文API存在之前。它基于一个称为存储的状态容器的概念,组件可以从该容器中作为 props 接收数据。更新存储区的唯一方法是向存储区发送一个操作,该操作被传递到一个reducer中。reducer接收操作和当前状态,并返回一个新状态,触发订阅的组件重新渲染。
38、React-Router工作原理?react-router-dom有哪些组件
路由器组件,路由匹配组件,导航组件
react-router 的依赖库history
1、BrowserHistory:用于支持 HTML5 历史记录 API 的现代 Web 浏览器(请参阅跨浏览器兼容性)
2、HashHistory:用于旧版Web浏览器\
3、MemoryHistory:用作参考实现,也可用于非 DOM 环境,如 React Native 或测试
BrowserHistory:pushState、replaceState
HashHistory:location.hash、location.replace
39、React 如何做到和 vue 中 keep-alive 的缓存效果
React Keep Alive 提供了 ,你必须把 放在 Provider 里面,并且每个 组件都必须拥有一个唯一的 key
40、React 有哪几种创建组件的方法
React 有三种构建组件的方式
1、React.createClass
2、ES6 class
3、无状态函数
41、React diff 原理
把树形结构按照层级分解,只比较同级元素。
列表结构的每个单元添加唯一的 key 属性,方便比较。
React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字)
合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty 到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制.
选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性能。
42、为什么虚拟 dom 会提高性能
虚拟dom相当于在js和真实dom中间加了一个缓存,利用dom diff算法避免了没有必要的dom操作,从而提高性能。
43、useCallback 和 useMemo 的使用场景
useCallback 和 useMemo 可以用来缓存函数和变量,提高性能,减少资源浪费。但并不是所有的函数和变量都需要用这两者来实现,他也有对应的使用场景。
我们知道 useCallback 可以缓存函数体,在依赖项没有变化时,前后两次渲染时,使用的函数体是一样的。它的使用场景是:
函数作为其他 hook 的依赖项时(如在 useEffect()中);函数作为 React.memo()(或 shouldComponentUpdate )中的组件的 props;主要是为了避免重新生成的函数,会导致其他 hook 或组件的不必要刷新。
useMemo 用来缓存函数执行的结果。如每次渲染时都要执行一段很复杂的运算,或者一个变量需要依赖另一个变量的运算结果,就都可以使用 useMemo()。
44、为什么 JSX 中 class 变成了 className?
因为在 JavaScript 里 class 是一个关键字,用来定义类。所以在 JSX 里不能再用 class 来表示 HTML 元素的类名了,就用 className 来代替,这样就不会和 JavaScript 的关键字冲突了。
45、什么是 React Diff,对比 Vue Diff?
React DiffReact 的 Diff 算法主要是基于两个假设:不同类型的元素会产生不同的树;开发人员可以通过设置key属性来告知 React 哪些元素在不同的渲染之间是稳定的。在对比时,React 会对新旧虚拟 DOM 树进行深度优先遍历,分层比较节点,当发现节点类型不同时,直接替换整个子树,当节点类型相同且有key时,会进行更细致的比较和更新。
Vue DiffVue 的 Diff 算法在比较节点时,同样会优先判断节点类型是否相同。在处理列表时也依赖key属性。不过 Vue 的 Diff 算法在某些细节上与 React 有所不同,例如在静态节点和动态节点的处理上,Vue 会对静态节点进行优化,尽量减少对静态节点的重复比较。
46、react合成事件
react的合成事件,屏蔽了浏览器自带的事件, 解决了浏览器的不兼容,
将事件绑定在document上,按照冒泡或者捕获的路径去收集真正的事件处理函数,在此过程中会先处理原生事件,然后当冒泡到document对象后 普通事件 是绑定在真实dom上
47、ajax 应该放在哪个生命周期?
在 React 类组件中,ajax 请求通常放在 componentDidMount 生命周期方法中。因为这个时候组件已经挂载到 DOM 上,可以进行数据的获取操作,并且不会引起额外的渲染。
在 React Hooks 中,ajax 请求通常放在 useEffect hooks 中。
48、说一下React Hooks在平时开发中需要注意的问题和原因?
React Hooks在使用时注意事项:
1、只能在React函数中使用(函数式组件或自定义hook)。
2、只能在函数最外层调用hook,不能包括在if,for等语句中或者子函数中。
3、useState中存储的是引用类型的数据时,修改state时,一定要返回新的引用。
原因:
Hooks专为函数组件的逻辑复用而设计所以只能用在函数式组件和自定义hooks。
hooks在调用的时候,需要确保先后调用顺序,一个顺序出问题,会导致整个程序的混乱。
如果在useState中存储的是引用类型,更新时不更引用地址时的话,React会认为我们没有更新数据,则不进行组件更新。
49、请结合React Router实现React项目的路由守卫
React实现路由拦截的基本思路还是利用Route的render函数,通过判断拦截条件来实现不同的组件的跳转,从而实现拦截
50、是否使用过React Portals,在什么场景下使用?
Portal提供了一种将子节点渲染到存在于父组件以外的DOM节点的优秀方案。