React相关总结

1.React的特性

React 是一个流行的JavaScript库,用于构建用户界面。它有几个核心特性:
组件化: React的核心思想是将用户界面拆分成独立的组件,每个组件具有自己的状态(state)和属性(props)。这种组件化开发使得代码更加模块化和可重用,同时也易于维护和测试。

虚拟DOM: React 使用虚拟DOM 来优化页面渲染。它通过比较前后两个虚拟DOM 树的差异,最小化浏览器中实际DOM 的操作,从而提高性能。

单向数据流: React使用单向数据流来管理组件之间的数据传递。父组件可以通过props将数据传递给子组件,子组件可以通过回调函数将数据传递回父组件。这种数据流动的方式使得组件之间的关系更加清晰可控,便于跟踪和调试。

JSX: JSX 是一种JavaScript 的语法扩展,允许在代码中直接编写类似HTML 的结构,这样可以更直观地描述用户界面的结构。

生命周期: React 组件具有生命周期方法,可以在组件不同阶段执行特定的操作,如组件加载时、更新时或卸载时执行清理工作。

状态管理: React 使用状态(state)来管理组件的内部数据,状态的变化触发界面的重新渲染,使得用户界面与数据保持同步。

这些特性使得React 成为构建交互式和可扩展的用户界面的强大工具。

2.React的生命周期

React 的生命周期方法是组件在不同阶段执行的特定函数。以下是 React 生命周期的详细解析:

1. 挂载阶段(Mounting):

a. constructor(props)

  • 组件被创建时调用
  • 用于初始化 state 和绑定方法

b. static getDerivedStateFromProps(props, state)

  • 在 render 之前调用
  • 用于根据 props 更新 state

c. render()

  • 必须实现的方法
  • 返回 JSX 描述 UI

d. componentDidMount()

  • 组件挂载到 DOM 后调用
  • 适合进行网络请求、DOM 操作等

2. 更新阶段(Updating):

a. static getDerivedStateFromProps(props, state)

  • 同挂载阶段

b. shouldComponentUpdate(nextProps, nextState)

  • 决定组件是否需要重新渲染
  • 可用于性能优化

c. render()

  • 同挂载阶段

d. getSnapshotBeforeUpdate(prevProps, prevState)

  • 在最近一次渲染输出之前调用
  • 用于获取更新前的 DOM 状态

e. componentDidUpdate(prevProps, prevState, snapshot)

  • 组件更新后调用
  • 可以操作 DOM,比较更新前后的 props

3. 卸载阶段(Unmounting):

a. componentWillUnmount()

  • 组件卸载前调用
  • 用于清理订阅、定时器等

4. 错误处理:

a. static getDerivedStateFromError(error)

  • 在后代组件抛出错误后调用
  • 用于渲染备用 UI

b. componentDidCatch(error, info)

  • 在后代组件抛出错误后调用
  • 用于记录错误信息

5. 新的生命周期方法(React 16.3+):

  • getDerivedStateFromProps
  • getSnapshotBeforeUpdate

6. 废弃的生命周期方法:

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

7. 函数组件的生命周期(通过 Hooks):

  • useEffect:相当于 componentDidMount、componentDidUpdate 和 componentWillUnmount 的组合
  • useLayoutEffect:在所有 DOM 变更之后同步调用
  • useMemo:用于性能优化,类似 shouldComponentUpdate
  • useCallback:用于性能优化,避免不必要的渲染

8. 生命周期的最佳实践:

  • 在 componentDidMount 中进行数据获取
  • 使用 shouldComponentUpdate 或 React.memo 进行性能优化
  • 在 componentWillUnmount 中清理资源
  • 使用错误边界处理潜在错误

9. 注意事项:

  • 避免在 render 方法中进行副作用操作
  • 不要在 componentWillUpdate 中使用 setState
  • 使用 getDerivedStateFromProps 时要小心,避免不必要的 state 更新

理解和正确使用生命周期方法对于开发高效、可维护的 React 应用至关重要。随着 React 的发展,Hooks 的引入为函数组件提供了类似的生命周期能力,使得组件逻辑更加灵活和可复用。

3.JavaScript的同步与异步任务详解

js中的任务,大致分为2类,一类是同步任务,另一类是异步任务
而异步任务,又分为宏任务微任务,这两个任务是两个队列,所以是先进先出的。

同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。

异步任务指的是,不进入主线程、而进入"任务队列"的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行

js代码在执行的时候,会先执行同步代码,遇到异步宏任务则将异步宏任务放入宏任务队列中,遇到异步微任务则将异步微任务放入微任务队列中,当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,微任务执行完毕后,再将异步宏任务从队列中调入主线程执行,一直循环至所有的任务执行完毕(完成一次事件循环EventLoop)。
宏任务(Macro-tasks):

  • setTimeout
  • setInterval
  • setImmediate (Node.js 环境)
  • requestAnimationFrame (浏览器环境)
  • I/O 操作
  • UI 渲染 (浏览器环境)
    微任务(Micro-tasks):
  • Promise.then/catch/finally
  • process.nextTick (Node.js 环境)
  • MutationObserver (浏览器环境)
  • queueMicrotask
    执行顺序:
  1. 执行同步代码,这属于宏任务
  2. 执行栈为空,查询是否有微任务需要执行
  3. 执行所有微任务
  4. 必要的话渲染 UI
  5. 开始下一轮 Event loop,执行宏任务中的异步代码

简而言之,执行顺序是:
同步代码 -> 微任务 -> 宏任务
重要的是要记住,在每个宏任务执行完成后,引擎会立即执行所有可用的微任务,然后再执行下一个宏任务。这就是为什么微任务通常比宏任务先执行的原因。
举个例子:

console.log('1'); // 同步代码

setTimeout(() => {
    console.log('2'); // 宏任务
}, 0);

Promise.resolve().then(() => {
    console.log('3'); // 微任务
});

console.log('4'); // 同步代码

输出顺序将会是:1, 4, 3, 2
理解这种执行顺序对于编写和调试异步代码非常重要,尤其是在处理复杂的异步操作时。

4.React中的hooks函数

React 的 Hooks 是 React 16.8 引入的一项功能,它允许你在函数组件中使用 state 和其他 React 特性,而无需编写类组件。Hooks 的出现极大地提升了函数组件的灵活性和可读性。下面详细介绍一些常用的 Hooks 及其用法:
1. useState
功能:用于在函数组件中添加状态。
用法

import React, { useState } from 'react';
function Counter() {
  // 声明一个状态变量 `count` 和一个更新该状态的函数 `setCount`
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

解释

  • useState 返回一个数组,第一个元素是当前状态值,第二个元素是更新状态的函数。
  • useState 接受初始状态作为参数(这里是 0),并返回当前状态和更新状态的函数。
    2. useEffect
    功能:处理副作用,例如数据获取、订阅和手动操作 DOM。
    用法
import React, { useEffect, useState } from 'react';
function DataFetcher() {
  const [data, setData] = useState(null);
  useEffect(() => {
    // 执行副作用操作:数据获取
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => setData(data));
    // 清理副作用:可选
    return () => {
      console.log('Cleanup');
    };
  }, []); // 空数组表示仅在组件挂载时执行一次
  return <div>{data ? `Data: ${data}` : 'Loading...'}</div>;
}

解释

  • useEffect 用于处理副作用操作(例如数据获取、DOM 操作等)。
  • 它接受两个参数:副作用函数和依赖数组。副作用函数会在组件挂载、更新时调用。
  • 依赖数组为空时,副作用函数仅在组件挂载时调用一次;如果依赖数组包含变量,当这些变量发生变化时副作用函数会重新执行。
  • 副作用函数可以返回一个清理函数,用于组件卸载时执行清理操作。
    3. useContext
    功能:用于在组件树中访问上下文(Context)。
    用法
import React, { createContext, useContext } from 'react';
// 创建一个上下文
const ThemeContext = createContext('light');

function ThemedComponent() {
  // 使用 useContext 获取上下文值
  const theme = useContext(ThemeContext);
  return <div>The current theme is {theme}</div>;
}
function App() {
  return (
    <ThemeContext.Provider value="dark">
      <ThemedComponent />
    </ThemeContext.Provider>
  );
}

解释

  • createContext 用于创建上下文对象。
  • useContext 接受上下文对象,并返回当前上下文的值。
  • 上下文值由上下文的 Provider 组件提供。
    4. useReducer
    功能:用于处理更复杂的状态逻辑。
    用法
import React, { useReducer } from 'react';

// 定义一个 reducer 函数
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  // 使用 useReducer 代替 useState
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
    </div>
  );
}

解释

  • useReducer 接受 reducer 函数和初始状态。
  • reducer 函数接收当前状态和 action,对状态进行更新并返回新状态。
  • useReducer 返回当前状态和 dispatch 函数,用于分发 actions。
    5. useCallback
    功能:用于缓存函数实例,防止不必要的重新渲染。
    用法
import React, { useCallback, useState } from 'react';

function ChildComponent({ onClick }) {
  console.log('ChildComponent rendered');
  return <button onClick={onClick}>Click me</button>;
}

function ParentComponent() {
  const [count, setCount] = useState(0);

  // 使用 useCallback 缓存 handleClick 函数
  const handleClick = useCallback(() => {
    console.log('Button clicked');
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <ChildComponent onClick={handleClick} />
    </div>
  );
}

解释

  • useCallback 用于缓存函数实例,以避免在每次渲染时创建新的函数。
  • 它接受一个回调函数和依赖数组。只有在依赖数组中的值发生变化时,回调函数才会重新创建。
    6. useMemo
    功能:用于缓存计算结果,避免不必要的计算。
    用法
import React, { useMemo, useState } from 'react';

function ExpensiveComponent({ number }) {
  // 模拟一个昂贵的计算
  const computedValue = useMemo(() => {
    console.log('Computing...');
    return number * 2;
  }, [number]);

  return <div>Computed Value: {computedValue}</div>;
}

function ParentComponent() {
  const [number, setNumber] = useState(1);

  return (
    <div>
      <button onClick={() => setNumber(number + 1)}>Increase Number</button>
      <ExpensiveComponent number={number} />
    </div>
  );
}

解释

  • useMemo 用于缓存计算结果,避免在每次渲染时重新计算。
  • 它接受一个计算函数和依赖数组。只有当依赖数组中的值发生变化时,计算函数才会重新执行。
    总结
    React 的 Hooks 提供了丰富的功能来管理状态和副作用,同时简化了组件逻辑。掌握这些 Hooks 的用法能够帮助你编写更加简洁、可维护的 React 代码。

5.前端优化有哪些手段

前端性能优化对提高网站的加载速度、响应速度以及用户体验非常重要。以下是一些常用的前端性能优化方法:

1. 减少HTTP请求
每个资源(CSS、JS、图片等)的请求都会增加页面加载时间,因此减少HTTP请求非常重要。
合并文件:将多个CSS或JS文件合并为一个,减少请求次数。
使用CSS Sprite:将多个小图标合并为一张图片,减少图片请求。

2. 使用CDN(内容分发网络)
CDN能将资源分发到离用户最近的服务器,从而加快资源的加载速度。

3. 文件压缩与最小化
通过压缩和最小化CSS、JavaScript和HTML文件,可以减少文件大小,提升加载速度。
CSS/JS压缩:使用工具如UglifyJS、CSSNano来压缩文件。
HTML压缩:移除HTML中的注释、空格等无用字符。

4. 图片优化
图片是网页中占用流量较大的部分,优化图片可以显著提高性能。
使用合适的图片格式:如使用WebP代替JPEG和PNG。
图片压缩:使用工具如TinyPNG、ImageOptim来减少图片文件大小。
延迟加载(Lazy Load):仅在需要时加载图片,减少初始页面的加载时间。

5. 启用浏览器缓存
通过设置适当的缓存策略,让浏览器缓存静态资源,避免每次访问页面时都重新下载资源。

Cache-Control: max-age=31536000

6. 异步加载JavaScript
将JavaScript文件设置为异步加载,避免阻塞页面的渲染。
使用asyncdefer属性,确保脚本不会阻塞HTML解析。

<script src="app.js" async></script>

7. 减少重绘和重排
重绘和重排会导致页面性能下降。以下是减少重绘和重排的方法:
避免频繁修改DOM:批量进行DOM操作,减少多次修改DOM的次数。
CSS优化:避免过多的CSS嵌套和复杂选择器。

8. 使用现代布局技术
使用CSS Grid、Flexbox等现代布局方式,减少对浮动和绝对定位的依赖,简化代码。

9. 优先加载关键内容
确保关键CSS和JavaScript尽快加载,而非关键内容可以延迟加载或异步加载。可以将关键CSS内联到HTML中。

10. 减少第三方库的依赖
尽量减少使用大型库或框架,如果只需要部分功能,可以使用更轻量化的替代方案。

总结
前端性能优化的目标是减少页面的加载时间、提高响应速度,并为用户提供更流畅的体验。通过减少HTTP请求、优化文件大小、合理使用缓存、减少DOM操作等方式,可以显著提升网页的性能。

6.React优化有哪些手段

在React中,优化性能可以通过以下方法实现,以确保应用运行更高效、响应更迅速:

1. 避免不必要的渲染
React组件的重复渲染是性能瓶颈之一。通过避免不必要的渲染可以提升性能。

  • 使用shouldComponentUpdate(类组件)或React.memo(函数组件):只有当props或state发生变化时,才触发组件的更新。

    const MyComponent = React.memo(function MyComponent(props) {
      return <div>{props.value}</div>;
    });
    
  • useCallbackuseMemo:对于函数和复杂计算结果,使用useCallbackuseMemo避免每次渲染时重新生成或计算。

    const memoizedCallback = useCallback(() => {
      doSomething(a, b);
    }, [a, b]);
    
    const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
    

2. 使用React的key来优化列表渲染
在列表渲染中,确保为每个元素提供一个唯一且稳定的key值。React利用key来高效识别变化的项,从而减少不必要的DOM更新。

{items.map(item => (
  <li key={item.id}>{item.name}</li>
))}

3. 代码分割与懒加载
使用动态import()和React的React.lazy()来实现代码分割与按需加载,从而减少初始页面的加载时间。

const LazyComponent = React.lazy(() => import('./LazyComponent'));

function App() {
  return (
    <React.Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
    </React.Suspense>
  );
}

4. 避免匿名函数和内联对象
每次渲染都会重新创建匿名函数和内联对象,导致组件不必要的重新渲染。使用useCallbackuseMemo来缓存这些函数和对象。

5. 批量处理State更新
React自动对多个setState调用进行批量处理,但在某些情况下(如异步回调中),你需要手动合并多次更新以减少渲染次数。

setState(prevState => ({
  ...prevState,
  count: prevState.count + 1
}));

6. 避免过大的组件树
将大组件拆分为多个小的功能组件,避免整个组件树重新渲染。保持组件粒度细化,也便于优化每个组件的性能。

7. 使用生产版本的React
确保在生产环境中使用React的生产构建版本。开发版本包含额外的调试信息和性能警告,会减慢应用的运行速度。

NODE_ENV=production npm run build

8. 使用Profiler工具
React提供了Profiler API来分析应用中的渲染性能。可以用它来了解哪些组件占用了过多的渲染时间,从而针对性地优化。

<React.Profiler id="App" onRender={(id, phase, actualDuration) => {
  console.log({ id, phase, actualDuration });
}}>
  <App />
</React.Profiler>

9. 虚拟化长列表
对于长列表,React可以使用虚拟化技术(如react-windowreact-virtualized),只渲染当前可见部分的列表项,减少不必要的DOM节点渲染。

import { FixedSizeList as List } from 'react-window';

const MyList = ({ items }) => (
  <List height={400} itemCount={items.length} itemSize={35}>
    {({ index, style }) => (
      <div style={style}>
        {items[index]}
      </div>
    )}
  </List>
);

10. Debouncing和Throttling事件
对于频繁触发的事件(如滚动、输入),使用debouncing或throttling技术减少事件处理的频率,从而减轻组件的渲染负担。

const handleScroll = useCallback(
  debounce(() => {
    // Do something on scroll
  }, 300),
  []
);

总结
React性能优化的关键在于减少不必要的渲染、充分利用React的内置机制如useMemouseCallbacklazy loading等,针对性地优化性能瓶颈。同时,可以借助Profiler和虚拟化工具来精准定位性能问题。

7.React中的虚拟DOM 和 diff算法原理介绍

React 的虚拟 DOM 和 diff 算法是其高效性能的核心所在。让我们详细地探讨一下它们的原理:
1. 虚拟 DOM(Virtual DOM)
虚拟 DOM 是 React 中的一个核心概念,它是真实 DOM 的一个轻量级的 JavaScript 对象表示。
原理:

  • 当组件的状态发生变化时,React 首先在内存中重新渲染整个 UI 的虚拟表示。
  • 这个新的虚拟 DOM 树会和之前的虚拟 DOM 树进行比较。
  • 通过比较,React 可以精确地知道哪些部分发生了变化。
  • 最后,React 只更新实际 DOM 中需要变化的部分。
    优势:
  • 减少了直接操作 DOM 的次数,提高了性能。
  • 允许 React 在不同平台上运行(如服务器端渲染或原生移动应用)。

2. Diff 算法
Diff 算法是 React 用来比较两个虚拟 DOM 树的方法,以确定需要进行哪些 DOM 操作。
原理:
React 的 diff 算法基于三个主要假设:

a) 两个不同类型的元素会产生不同的树。

  • 如果根元素类型不同,React 会直接销毁旧树,创建新树。

b) 开发者可以通过 key 属性暗示哪些子元素可能是稳定的。

  • 使用 key 可以帮助 React 识别哪些元素被修改、添加或删除。

c) 对于同级的子节点,React 使用 key 进行对比。

  • 如果没有 key,React 会按顺序对比。

diff 过程:

  1. 对比根元素:

    • 如果根元素类型不同,React 会销毁旧树,创建新树。
    • 如果类型相同,保留 DOM 节点,仅比对和更新有改变的属性。
  2. 对比组件元素:

    • 如果是同一类型的组件,React 更新该组件的 props,并调用 componentWillReceiveProps() 和 componentWillUpdate() 方法。
    • 然后调用 render() 方法,diff 算法将在之前的结果和新的结果中进行递归。
  3. 对比子元素:

    • React 会同时遍历两个子元素列表,产生差异时生成一个 mutation。
    • 使用 key 可以让这个过程更高效。

优化策略:

  • 使用 key:帮助 React 识别哪些项目被修改、添加或删除。
  • 保持组件的 DOM 结构稳定:避免不必要的重建。
  • 使用 PureComponent 或 React.memo:减少不必要的渲染。

总结:
虚拟 DOM 和 diff 算法共同工作,使得 React 能够高效地更新 UI。虚拟 DOM 提供了一个轻量级的 UI 表示,而 diff 算法则精确地计算出需要更新的部分,最小化了实际 DOM 操作,从而提高了应用的性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值