目录
1、什么是React?它的特点是什么?
2、解释一下虚拟DOM(Virtual DOM)的概念以及它的工作原理。
3、什么是组件(Component)?如何定义一个React组件?
4、什么是JSX?它与HTML的区别是什么?如何在React中渲染元素?举例说明。
5、react组件通信有哪些方式。
6、什么是React的状态(State)?如何使用状态管理组件的数据?
7、什么是React的Props?如何向组件传递数据和方法?
8、react的生命周期是什么?React 16.3之后的生命周期发生了什么变化?
9、react 常用的hooks有哪些。react hook的优缺点?
10、什么是React Router?如何实现在React中的导航和路由?
11、如何通过React Router实现路由懒加载(Lazy Loading)?
12、什么是状态提升(State Lifting)?为什么要使用它?
13、什么是React的上下文(Context),如何在组件间共享数据?
14、如何在React中应用样式?有哪些不同的方法?
15、你了解CSS-in-JS库吗?例如,styled-components和Emotion。
16、解释一下React中的错误边界(Error Boundaries)。
17、如何优化React应用的性能?
18、什么是单页面应用(SPA)?它的优缺点是什么?
19、useRef、ref、forwardsRef 的区别是什么?
20、如何在 React 组件中进行编程式导航?
21、如何实现路由重定向?
22、如何传递参数给路由组件?
23、React Router 中常用的组件有哪些?
24、react中父组件调用子组件的方法
25、useEffect和useLayoutEffect区别在哪
26、页面首屏加载优化
27、如何减少页面中的HTTP请求?如何优化网页加载速度?提供一些技巧。
28、React高阶组件用途
29、useEffect函数中,返回一个函数,会在什么时候执行?如果useEffect有第二个参数,返回的函数又在什么时候执行?
React 是用于构建 Web 和原生交互界面的库。
特点:
- 组件化(组件式开发,提高代码利用率 );
- 单向数据流(单向数据流比双向绑定更安全,且更快; );
- 虚拟DOM;
- JSX语法;
- 声明式编程;
虚拟 DOM 是一个 JS对象。是对真实 DOM 的一种抽象表示。
工作原理:
初始渲染时候,将组件
JSX
通过babel
最终转化成React.createElement
;转化成虚拟 DOM 树。状态改变的时候,react 会重新构建虚拟 DOM 树;
对比更新,react 通过 diff 算法,对比新旧 DOM 树,找出差异的部分。
然后将此部分进行批量更新,再通过 react.render() 渲染到真实 DOM 上;
React 组件是一段可以 使用标签进行扩展 的 JavaScript 函数。
有两种声明方式,函数式组件和类组件。现在常用的是函数式组件。
JSX 是 JavaScript 语法扩展,可以让你在 JavaScript 文件中书写类似 HTML 的标签。
JSX 规则
1. 只能返回一个根元素
2. 标签必须闭合
3. 使用驼峰式命名法给 大部分属性命名!
其渲染流程如下所示:
使用React.createElement或JSX编写React组件,实际上所有的 JSX 代码最后都会转换成React.createElement(...) ,Babel帮助我们完成了这个转换的过程。
createElement函数对key和ref等特殊的props进行处理,并获取defaultProps对默认props进行赋值,并且对传入的孩子节点进行处理,最终构造成一个虚拟DOM对象
ReactDOM.render将生成好的虚拟DOM渲染到指定容器上,其中采用了批处理、事务等机制并且对特定浏览器进行了性能优化,最终转换为真实DOM
1. 父组件向子组件传值:通过props将数据传递给子组件。在父组件中设置子组件的属性,并将需要传递的值作为属性值传递给子组件。
2. 子组件向父组件传值:通过在子组件中定义一个回调函数,然后在子组件中触发该回调函数并将需要传递的值作为参数传递给父组件。
3. 兄弟组件间传值:如果两个兄弟组件之间需要进行数据通信,可以通过共同的父组件作为中介,在父组件中维护一个状态,并将状态作为props传递给兄弟组件。
4. 使用Context API传值:Context API是React提供的一种跨层级传递数据的方式。通过创建一个Context对象,将需要共享的数据存储在该对象中,并在需要访问数据的组件中使用Context.Provider包裹,并通过Context.Consumer来获取数据。
5. 使用Redux或MobX进行状态管理:Redux和MobX是常用的状态管理库,它们可以在整个应用的任意组件中共享数据,从而实现组件间的值传递和状态管理。
其实就是组件的属性。可以自行维护的数据,是一个对象。useState or this.setState。
props 是外部传递给组件的,在组件内部是不可修改的。是一个对象。
如何向组件传递--:详见第五题。
挂载阶段:
constructor
getDerivedStateFromProps
render
componentDidMount更新阶段:
getDerivedStateFromProps
shouldComponentUpdate
render
componentDidUpdate
卸载阶段:componentWillUnmount,componentDidUnmount
新版的生命周期减少了以下三种方法:
componentWillMount
componentWillReceiveProps
componentWillUpdate
同时也新增了两个生命周期函数:
getDerivedStateFromProps
getSnapshotBeforeUpdate
1. useState: 用于在函数组件中添加状态。
2. useEffect: 用于在组件渲染完成后执行副作用操作,如数据获取、订阅等。
3. useContext: 用于在组件中访问React的Context。
4. useReducer: 类似于Redux中的reducer,用于处理复杂的状态逻辑。
5. useCallback: 用于缓存函数,避免不必要的重新创建。防止子组件重复渲染。
6. useMemo: 用于缓存计算结果,避免不必要的重复计算。
7. useRef: 用于在函数组件之间共享可变值。
8. useLayoutEffect: 与useEffect类似,但它会在DOM更新之后同步触发。
9. useImperativeHandle: 用于自定义暴露给父组件的实例值。
10. useDebugValue: 用于在开发者工具中显示自定义hook的label。优点:
1、更容易复用代码
这点应该是react hooks最大的优点,它解决了类组件有些时候难以复用逻辑的问题。通过自定义hooks,便可以轻松复用逻辑。
2、清爽的代码风格
函数式编程风格,函数式组件、状态保存在运行环境、每个功能都包裹在函数中,整体风格更清爽,更优雅
3、代码量更少
向props或状态取值更加方便,函数组件的取值都从父级作用域直接取,而类组件需要先访问实例引用this,再访问其属性state和props,多了一步
更改状态也变得更加简单, this.setState({ count:xxx })变成 setCount(xxx)。
更容易发现无用的状态和函数
对比类组件,函数组件里面的unused状态和函数更容易被发现
4、更容易拆分组件
写函数组件的时候,你会更愿意去拆分组件,因为函数组件写起小组件比类组件要省事。缺点:
在函数式组件中不可以进行使用;
不要在循环、条件或嵌套函数中调用 Hook;
状态不同步
不好用的useEffect, 状态更新有有多种依赖的情况下。
这绝对可以成为摒弃react hooks的理由。函数的运行是独立的,每个函数都有一份父级作用域。当我们处理复杂逻辑的时候,经常会碰到状态不同步的问题
react-router
等前端路由的原理大致相同,可以实现无刷新的条件下切换显示不同的页面路由的本质就是页面的
URL
发生改变时,页面的显示结果可以根据URL
的变化而变化,但是页面不会刷新
BrowserRouter:一个使用HTML5 history API实现的路由器组件,用于在Web应用中处理路由。
HashRouter:一个使用URL hash值实现的路由器组件,用于在不支持HTML5 history API的Web应用中处理路由。
Route:定义了路由匹配规则及对应的组件,可以在路由器中使用。
Switch:用于渲染与当前URL匹配的第一个Route或Redirect,只能包含Route或Redirect组件。
Link:用于创建导航链接,点击后会更新URL,触发路由的切换。
NavLink:与Link类似,但在匹配当前URL时会添加指定的样式。
React Router 4+ 版本开始支持路由懒加载。可以使用 React.lazy 和 Suspense 组件来动态地加载路由组件。
例如:
const MyComponent = React.lazy(() => import('./MyComponent'))
。
将其状态移动到所需它的组件最接近的共同祖先组件中称之为状态提升。
符合数据的单向传递思想。
通过使用
React.createContext
创建一个context
通过provide
用于给后代组件传递数据。后代通过Consumer
组件或者或者使用contextType
属性接收也可以通过useContext();接收。
在组件内直接使用
组件中引入 .css 文件
组件中引入 .module.css 文件
CSS in JS
// style.js
export const SelfLink = styled.div`
height: 50px;
border: 1px solid red;
color: yellow;
`;
export const SelfButton = styled.div`
height: 150px;
width: 150px;
color: ${props => props.color};
background-image: url(${props => props.src});
background-size: 150px 150px;
`;
// css in js
import React, { Component } from "react";
import { SelfLink, SelfButton } from "./style";
class Test extends Component {
constructor(props, context) {
super(props);
}
render() {
return (
app.js
SelfButton
);
}
}
export default Test;
1、
try{
} catch {
}
2、componentDidCatch()
错误边界在渲染期间、生命周期方法和整个组件树的构造函数中捕获错误,形成错误边界组件的两个条件:
使用了 static getDerivedStateFromError()
使用了 componentDidCatch()
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染能够显示降级后的 UI
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// 你同样可以将错误日志上报给服务器
logErrorToMyService(error, errorInfo);
}
render() {
if (this.state.hasError) {
// 你可以自定义降级后的 UI 并渲染
return Something went wrong.
;
}
return this.props.children;
}
}
下面这些情况无法捕获到异常:
事件处理
异步代码
服务端渲染
自身抛出来的错误
3、除此之外还可以通过监听onerror事件
window.addEventListener('error', function(event) { ... })
1. 使用 React.memo() 或 shouldComponentUpdate() 来避免不必要的组件重渲染。这些方法可以帮助你确定是否需要重新渲染组件,以提高性能。
2. 使用 keys 属性来为列表渲染提供稳定的身份标识。这样做可以减少不必要的 DOM 操作,提高列表渲染的性能。
3. 使用虚拟化列表(如 react-virtualized 或 react-window)来处理大型的列表渲染,只渲染可见部分,从而减少 DOM 元素数量,提高性能。
4. 避免在 render 方法中进行昂贵的计算或操作。可以将这些计算或操作放在组件的 constructor 或 componentDidMount 等生命周期方法中进行,避免在每次渲染时执行。
5. 使用生命周期方法或 useEffect 钩子函数来管理组件的副作用,例如订阅和取消订阅事件、请求数据等。确保在组件卸载时正确清理这些副作用。
6. 使用 React Profiler 来识别应用中的性能瓶颈,并针对性地进行优化。
7. 使用 webpack、Parcel 或 Rollup 等打包工具进行代码分割和懒加载,以按需加载组件和资源,减少初始加载时间。
8. 对于频繁更新的数据,使用 useReducer 或 Immutable.js 等工具来管理状态,避免不必要的重新渲染。
9. 使用 React DevTools 来分析组件树,检查组件的渲染次数以及更新所花费的时间,以帮助你找到性能瓶颈。
Web单页应用就是指只有一个Web页面作为入口的应用 在浏览器中运行期间不会重新加载页面。
优点:
具有桌面应用的即时性、网站的可移植性和可访问性
用户体验好、快,内容的改变不需要重新加载整个页面
良好的前后端分离,分工更明确
缺点:
不利于搜索引擎的抓取
首次渲染速度相对较慢
useRef:
创建的ref对象可以存储任何可变值,而且修改ref对象不会导致组件重新渲染。这使得它非常适合存储和访问DOM元素引用或其他不希望引发重新渲染的数据。ref:在React的旧版本中,可以使用
ref
属性来创建和访问DOM元素的引用。例如,通过可以创建一个DOM引用,但这是React的旧API。不建议使用。
forwardsRef:用于转发ref:
forwardRef
是用于在React组件之间传递refs的高阶函数。通常与React.forwardRef()
方法一起使用,以允许一个组件接收ref并将其传递给其子组件。
React Router 提供了 withRouter 高阶组件,可以将路由相关的属性注入到组件的 props 中。
通过调用 props.history.push('/path') 可以进行编程式导航。
React Router 提供了 Redirect 组件来实现路由重定向。可以在需要重定向的地方使用 Redirect 组件并指定目标路径。
React Router 支持在 URL 中传递参数,可以通过以下方式将参数传递给路由组件:
在路由规则中使用动态路径参数:
。
通过查询参数传递参数:
User
。
BrowserRouter:使用 HTML5 History API 实现路由导航。
HashRouter:使用 URL 的 hash 部分实现路由导航。
Route:定义一个路由规则,指定 URL 对应的组件。
Switch:包裹多个 Route,只渲染匹配到的第一个组件。
Link:生成一个链接,点击后触发路由导航。
子组件通过 useImperativeHandle 定义暴露给 父组件的实例值和方法,通过 forwardsRef 转发子组件,父组件通过 ref 获取子组件的实例,然后调用。
基本一致,但是如有有直接操作DOM样式或者引起DOM样式更新场景出现 更推荐使用useLayoutEffect,但他容易造成阻塞,所以通常情况用useEffect比较好。
页面首屏加载优化是指通过一些技术手段来减少页面加载时间,提高用户体验。以下是几种常见的页面首屏加载优化方法:
压缩和合并资源:减小HTML、CSS和JavaScript文件的大小,并将多个文件合并成一个文件,以减少网络请求次数。
图片优化:使用适当的图片格式(如JPEG、PNG、WebP),并对图片进行压缩,以减小图片的文件大小。
延迟加载:将页面上的非首屏元素延迟加载,只有当用户滚动到可见区域时才加载对应的内容,以减少首屏所需加载的资源量。
骨架屏(Skeleton Screen):在页面加载过程中,先展示出页面的大致结构(灰色占位图),使用户感知到页面正在加载,提高用户体验。
使用缓存:合理设置浏览器缓存,利用缓存技术来减少服务器的请求次数,加快页面加载速度。
异步加载:将一些不影响页面渲染的资源,如统计代码、广告代码等,采用异步加载方式,不阻塞页面首屏的渲染。
减少页面中的HTTP请求和优化网页加载速度是提高网页性能的关键因素之。以下是一些技巧:
合并文件:将多个CSS和JavaScript文件合并为一个文件,减少HTTP请求次数。这可以通过工具自动化完成,如Webpack或Gulp。
压缩文件:使用压缩算法来减小文件大小,例如使用Gzip或Brotli来压缩CSS和JavaScript文件。压缩后的文件可以更快地加载。
使用CSS Sprites:将多个小的图像合并为一个大图像,并使用CSS的background-position属性来显示所需的图像。这样可以减少图像请求次数。
延迟加载:将不是首次显示的内容(如图片、JavaScript)延迟加载,当用户滚动到它们时再加载。这可以通过使用延迟加载插件或懒加载技术来实现。
缓存机制:使用缓存来存储静态资源,如CSS、JavaScript和图像文件。这样,当用户再次访问网页时,这些资源可以从缓存中加载,而不是重新下载。
使用CDN:使用内容分发网络(CDN)来分发静态资源,将它们缓存在离用户更近的服务器上。这可以减少资源加载时间。
优化图像:使用适当的图像格式(如JPEG、PNG、WebP)和压缩级别来减小图像文件大小。可以使用图像优化工具,如PhotoShop或在线压缩工具。
减少重定向:避免使用过多的重定向,因为每次重定向都需要进行额外的HTTP请求。
启用浏览器缓存:通过设置适当的响应头,启用浏览器缓存。这样可以使浏览器在后续访问中从缓存中加载页面,而不是发送HTTP请求。
使用异步加载:将不会阻塞页面渲染的JavaScript代码放在异步脚本中,以避免阻塞页面的加载。
这些技巧可以帮助减少HTTP请求和优化网页加载速度,提高用户体验和页面性能。
React高阶组件(Higher-Order Components, HOC)是一种在React中复用组件逻辑的技术。它实际上是一个函数,接受一个组件作为参数,并返回一个新的经过增强的组件。
HOC的主要用途包括以下几点:
代码复用:HOC可以将一些通用的逻辑(例如:数据获取、鉴权、路由导航等)从组件中提取出来,然后通过传入不同的组件来实现代码复用。
状态管理:通过HOC,可以将一些共享的状态(例如:全局状态、用户登录状态等)注入到多个组件中,从而实现状态的共享和管理。
控制组件行为:HOC可以通过包装被传入的组件,来控制组件的渲染行为、事件处理等。例如,可以通过HOC来实现表单验证、性能优化等功能。
渲染劫持:通过HOC,可以修改组件的渲染输出,以满足特定的需求。例如,可以通过HOC来实现路由守卫、条件渲染等功能。
总的来说,React高阶组件是一种非常灵活和强大的技术,可以帮助我们在开发中提高代码复用性、实现状态管理和控制组件行为等方面带来很多好处。
先执行return内的内容,再执行return外的内容。