【React】精选5题

这篇具有很好参考价值的文章主要介绍了【React】精选5题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

第1题:简述下 React 的生命周期?每个生命周期都做了什么?

【React】精选5题,react.js,前端,javascript

React 组件的生命周期可以分为三个阶段:挂载阶段、更新阶段和卸载阶段。每个生命周期方法都有特定的目的和功能。

  1. 挂载阶段:

    • constructor:组件的构造函数,在组件被创建时调用,用于初始化状态和绑定方法。
    • static getDerivedStateFromProps:在组件实例化和每次接收新的 props 时被调用,用于根据新的 props 更新状态。
    • render:根据组件的状态和属性返回 JSX 元素。
    • componentDidMount:在组件被挂载到 DOM 后立即调用,可以进行异步数据获取、订阅事件等操作。
  2. 更新阶段:

    • static getDerivedStateFromProps:在接收到新的 props 或 state 时被调用,用于根据新的 props 或 state 更新状态。
    • shouldComponentUpdate:在组件更新前被调用,用于控制组件是否需要重新渲染,默认返回 true。
    • render:根据组件的状态和属性返回 JSX 元素。
    • getSnapshotBeforeUpdate:在 render 方法之后、更新 DOM 之前被调用,用于获取更新前的 DOM 快照。
    • componentDidUpdate:在组件更新后被调用,可以进行 DOM 操作或发送网络请求等操作。
  3. 卸载阶段:

    • componentWillUnmount:在组件被卸载前调用,可以进行清理操作,如取消订阅、清除定时器等。

除了上述生命周期方法,还有一些其他的生命周期方法,如错误边界相关的 componentDidCatch 方法,用于捕获子组件中的错误。

需要注意的是,由于 React Hooks 的引入,部分生命周期方法已经不再推荐使用。可以使用 useEffect Hook 来代替 componentDidMount、componentDidUpdate 和 componentWillUnmount。

具体介绍

render()

render() 方法是 class 组件中唯一必须实现的方法。当 render 被调用时,它会检查 this.props 和 this.state 的变化并返回以下类型之一:

  • React 元素。
    通常通过 JSX 创建。例如,<div /> 会被 React 渲染为 DOM 节点,<MyComponent />会被 React 渲染为自定义组件,无论是 <div /> 还是 <MyComponent /> 均为 React 元素。
  • 数组或 fragments。 使得 render 方法可以返回多个元素。欲了解更多详细信息,请参阅 fragments 文档。
  • Portals。可以渲染子节点到不同的 DOM 子树中。欲了解更多详细信息,请参阅有关 portals 的文档
  • 字符串或数值类型。它们在 DOM 中会被渲染为文本节点
  • 布尔类型或 null。什么都不渲染。(主要用于支持返回 test && 的模式,其中 test 为布尔类型。)
    render() 函数应该为纯函数,这意味着在不修改组件 state 的情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。

如需与浏览器进行交互,请在 componentDidMount() 或其他生命周期方法中执行你的操作。保持 render() 为纯函数,可以使组件更容易思考。
React中,Portal是一种机制,用于将组件的渲染结果插入到DOM树的不同位置,而不是直接插入到其父组件的DOM节点中。这在某些情况下非常有用,例如当你需要在React组件的层次结构之外渲染内容时。

使用Portal的步骤如下:

  1. 导入React和ReactDOM,因为Portal需要ReactDOM来渲染到不同的DOM位置。
import React from 'react';
import ReactDOM from 'react-dom';
  1. 在组件中创建一个容器元素,用于渲染Portal内容。这个容器元素可以是任何有效的DOM元素,但通常会在组件的顶层进行创建。
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.portalContainer = document.createElement('div');
  }

  componentDidMount() {
    document.body.appendChild(this.portalContainer);
  }

  componentWillUnmount() {
    document.body.removeChild(this.portalContainer);
  }

  render() {
    return null; // Portal不会渲染任何内容,它只是提供一个容器
  }
}
  1. 在组件需要的地方使用Portal进行渲染。使用ReactDOM.createPortal方法将组件的渲染结果渲染到创建的容器元素中。
class MyComponent extends React.Component {
  // ...

  render() {
    return ReactDOM.createPortal(
      <div>Portal内容</div>,
      this.portalContainer
    );
  }
}

在上面的例子中,我们在MyComponent组件的顶层创建了一个容器元素this.portalContainer。在组件的render方法中,使用ReactDOM.createPortal方法将一个包含内容的div元素渲染到这个容器元素中。

请注意,当组件被卸载时,需要手动从DOM中移除容器元素,以防止内存泄漏。在上面的例子中,我们在componentWillUnmount生命周期方法中移除了容器元素。

通过使用Portal,我们可以在React组件的层次结构之外渲染内容,这为处理一些特殊情况提供了更大的灵活性。

constructor()

如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。

在 React 组件挂载之前,会调用它的构造函数。在为 React.Component 子类实现构造函数时,应在其他语句之前前调用 super(props)。否则,this.props 在构造函数中可能会出现未定义的 bug。
通常,在 React 中,构造函数仅用于以下两种情况:
通过给 this.state 赋值对象来初始化内部 state。

  • 为事件处理函数绑定实例
  • 在 constructor() 函数中不要调用 setState() 方法。如果你的组件需要使用内部 state,请直接在构造函数中为 this.state 赋值初始 state。

只能在构造函数中直接为 this.state 赋值。如需在其他方法中赋值,你应使用 this.setState() 替代。

要避免在构造函数中引入任何副作用或订阅。如遇到此场景,请将对应的操作放置在 componentDidMount 中。

componentDidMount()

componentDidMount() 会在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。

这个方法是比较适合添加订阅的地方。如果添加了订阅,请不要忘记在 componentWillUnmount() 里取消订阅

你可以在 componentDidMount() 里直接调用 setState()。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在 render() 两次调用的情况下,用户也不会看到中间状态。请谨慎使用该模式,因为它会导致性能问题。通常,你应该在 constructor() 中初始化 state。如果你的渲染依赖于 DOM 节点的大小或位置,比如实现 modals 和 tooltips 等情况下,你可以使用此方式处理。

componentDidUpdate()

componentDidUpdate() 会在更新后会被立即调用。首次渲染不会执行此方法。

当组件更新后,可以在此处对 DOM 进行操作。如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求。(例如,当 props 未发生变化时,则不会执行网络请求)。

componentDidUpdate(prevProps) {
  // 典型用法(不要忘记比较 props):
  if (this.props.userID !== prevProps.userID) {
    this.fetchData(this.props.userID);
  }
}

你也可以在 componentDidUpdate() 中直接调用 setState(),但请注意它必须被包裹在一个条件语句里,正如上述的例子那样进行处理,否则会导致死循环。它还会导致额外的重新渲染,虽然用户不可见,但会影响组件性能。不要将 props “镜像”给 state,请考虑直接使用 props。 欲了解更多有关内容,请参阅为什么 props 复制给 state 会产生 bug。

如果组件实现了 getSnapshotBeforeUpdate() 生命周期(不常用),则它的返回值将作为 componentDidUpdate() 的第三个参数 “snapshot” 参数传递。否则此参数将为 undefined。

componentWillUnmount()

componentWillUnmount() 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。

componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。

shouldComponentUpdate()

根据 shouldComponentUpdate() 的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。默认行为是 state 每次发生变化组件都会重新渲染。大部分情况下,你应该遵循默认行为。

当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。返回值默认为 true。首次渲染或使用 forceUpdate() 时不会调用该方法。

此方法仅作为性能优化的方式而存在。不要企图依靠此方法来“阻止”渲染,因为这可能会产生 bug。你应该考虑使用内置的 PureComponent 组件,而不是手动编写 shouldComponentUpdate()。PureComponent 会对 props 和 state 进行浅层比较,并减少了跳过必要更新的可能性。

如果你一定要手动编写此函数,可以将 this.props 与 nextProps 以及 this.state 与nextState 进行比较,并返回 false 以告知 React 可以跳过更新。请注意,返回 false 并不会阻止子组件在 state 更改时重新渲染。

我们不建议在 shouldComponentUpdate() 中进行深层比较或使用 JSON.stringify()。这样非常影响效率,且会损害性能。

目前,如果 shouldComponentUpdate() 返回 false,则不会调用 UNSAFE_componentWillUpdate(),render() 和 componentDidUpdate()。后续版本,React 可能会将 shouldComponentUpdate 视为提示而不是严格的指令,并且,当返回 false 时,仍可能导致组件重新渲染。

static getDerivedStateFromProps()

getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。

此方法适用于罕见的用例,即 state 的值在任何时候都取决于 props。例如,实现 组件可能很方便,该组件会比较当前组件与下一组件,以决定针对哪些组件进行转场动画。

派生状态会导致代码冗余,并使组件难以维护。 确保你已熟悉这些简单的替代方案:

如果你需要执行副作用(例如,数据提取或动画)以响应 props 中的更改,请改用 componentDidUpdate。
如果只想在 prop 更改时重新计算某些数据,请使用 memoization helper 代替。
如果你想在 prop 更改时“重置”某些 state,请考虑使组件完全受控或使用 key 使组件完全不受控代替。
此方法无权访问组件实例。如果你需要,可以通过提取组件 props 的纯函数及 class 之外的状态,在getDerivedStateFromProps()和其他 class 方法之间重用代码。

请注意,不管原因是什么,都会在每次渲染前触发此方法。这与 UNSAFE_componentWillReceiveProps 形成对比,后者仅在父组件重新渲染时触发,而不是在内部调用 setState 时。

getSnapshotBeforeUpdate()

getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期方法的任何返回值将作为参数传递给 componentDidUpdate()。

此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。

应返回 snapshot 的值(或 null)。

Error boundaries

Error boundaries 是 React 组件,它会在其子组件树中的任何位置捕获 JavaScript 错误,并记录这些错误,展示降级 UI 而不是崩溃的组件树。Error boundaries 组件会捕获在渲染期间,在生命周期方法以及其整个树的构造函数中发生的错误。

如果 class 组件定义了生命周期方法 static getDerivedStateFromError() 或 componentDidCatch() 中的任何一个(或两者),它就成为了 Error boundaries。通过生命周期更新 state 可让组件捕获树中未处理的 JavaScript 错误并展示降级 UI。

仅使用 Error boundaries 组件来从意外异常中恢复的情况;不要将它们用于流程控制。

static getDerivedStateFromError()

此生命周期会在后代组件抛出错误后被调用。 它将抛出的错误作为参数,并返回一个值以更新 state。

componentDidCatch()

此生命周期在后代组件抛出错误后被调用。 它接收两个参数:

error —— 抛出的错误。
info —— 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息。
componentDidCatch() 会在“提交”阶段被调用,因此允许执行副作用。 它应该用于记录错误之类的情况。

React 的开发和生产构建版本在 componentDidCatch() 的方式上有轻微差别。

在开发模式下,错误会冒泡至 window,这意味着任何 window.onerror 或 window.addEventListener(‘error’, callback) 会中断这些已经被 componentDidCatch() 捕获的错误。

相反,在生产模式下,错误不会冒泡,这意味着任何根错误处理器只会接受那些没有显式地被 componentDidCatch() 捕获的错误。

第2题:React 错误边界是什么?

React 错误边界(Error Boundaries)是 React 组件中的一种特殊组件,用于捕获并处理子组件在渲染过程中抛出的 JavaScript 错误,以防止整个应用程序崩溃。

当一个错误边界组件包裹在子组件中时,它会监视子组件的渲染过程。如果子组件在渲染期间抛出了 JavaScript 错误(包括在生命周期方法、构造函数或渲染方法中的错误),错误边界组件会捕获该错误并显示备用的 UI,而不是导致整个应用程序崩溃。

错误边界组件是通过定义特定的生命周期方法 componentDidCatch(error, info) 来实现的。当子组件抛出错误时,React 会调用错误边界组件的 componentDidCatch 方法,并将错误信息和错误堆栈作为参数传递给该方法。在 componentDidCatch 方法中,你可以选择如何处理错误,例如显示错误信息或记录错误。

要创建一个错误边界组件,你可以定义一个继承自 React.Component 的类,并实现 componentDidCatch 方法。下面是一个简单的错误边界组件的示例:

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  componentDidCatch(error, info) {
    this.setState({ hasError: true });
    // 在这里可以处理错误,例如显示错误信息或记录错误
    console.error(error);
  }

  render() {
    if (this.state.hasError) {
      // 显示备用的 UI
      return <div>Oops, something went wrong.</div>;
    }
    return this.props.children;
  }
}

在你的应用程序中,你可以将错误边界组件包裹在其他组件中,以捕获并处理错误。例如:

<ErrorBoundary>
  <MyComponent />
</ErrorBoundary>

在这个示例中,如果 MyComponent 抛出了错误,错误边界组件 ErrorBoundary 将会捕获错误并显示备用的 UI。

需要注意的是,错误边界组件只能捕获其子组件的错误,而不能捕获其自身的错误或其他同级组件的错误。

第3题:为什么不能直接使用 this.state 改变数据?

在 React 中,不能直接使用 this.state 来改变组件的状态数据,而是应该使用 setState 方法。

主要原因是为了保证 React 组件的可预测性和性能优化。直接修改 this.state 的值会绕过 React 的状态更新机制,导致 React 无法感知到状态的变化,从而无法触发组件的重新渲染。这样可能会导致组件的 UI 不会正确地更新,且可能引发其他潜在的问题。

相反,React 提供了 setState 方法来更新组件的状态。setState 方法接收一个对象或一个函数作为参数,用于更新组件的状态。React 会将新的状态合并到当前状态中,并触发组件的重新渲染。通过 setState 方法更新状态,React 能够正确地跟踪状态的变化,并在必要时重新渲染组件。

此外,setState 方法是异步的,React 会对多次连续的状态更新进行批处理,以提高性能。如果需要在状态更新后执行某些操作,可以将回调函数作为 setState 方法的第二个参数,或者使用 componentDidUpdate 生命周期方法。

总结起来,使用 setState 方法来更新状态可以确保 React 正确地跟踪状态的变化,并触发组件的重新渲染,以保证组件的可预测性和性能优化。

第4题:React 中如果绑定事件使用匿名函数有什么影响?

在 React 中,如果使用匿名函数来绑定事件,会有一些影响。每当组件重新渲染时,匿名函数会被重新创建,这意味着每次渲染时都会生成一个新的函数实例。这可能会导致性能问题,特别是在具有大量子组件的情况下。

由于每个函数实例都被认为是一个新的引用,React 在进行虚拟 DOM 比较时会认为事件处理程序已经发生了变化。这将导致 React 重新渲染组件和子组件,即使实际上事件处理程序的功能没有发生任何变化。

为了避免这个问题,最好使用具名函数来定义事件处理程序,并将其作为属性传递给组件。这样,在组件重新渲染时,React 将会识别到事件处理程序是同一个引用,并且不会触发不必要的重新渲染。

class Demo {
  render() {
    return <button onClick={(e) => {
      alert('我点击了按钮')
    }}>
      按钮
    </button>
  }
}

这样的写法,因为使用的是匿名函数,所以组件每次都会认为是一个新的 props,不会使用缓存优化,在性能上会有一定的损耗。

第5题:React 的事件代理机制是什么?

React 的事件代理机制是指在顶层使用单一的事件监听器来处理所有的事件,并通过事件冒泡机制将事件传递给正确的组件进行处理。这种机制可以提高性能并减少内存占用。

在 React 中,你可以通过将事件处理程序绑定到组件的属性上来使用事件代理。例如,你可以将一个名为 onClick 的事件处理程序绑定到一个按钮组件上:

<button onClick={handleClick}>Click me</button>

在上面的示例中,handleClick 是一个具名函数,它将作为 onClick 属性传递给按钮组件。当按钮被点击时,React 将会在顶层监听到该事件,并将事件传递给 handleClick 函数进行处理。

在事件处理程序中,你可以访问事件对象,使用 event 参数来获取相关信息,例如:

function handleClick(event) {
  console.log('Button clicked!');
  console.log('Event:', event);
}

通过事件对象,你可以获取事件的类型、目标元素等信息,并执行相应的操作。

需要注意的是,React 使用合成事件来包装原生事件,并提供了一些额外的功能,如跨浏览器兼容性和性能优化。因此,你可以放心地使用 React 的事件代理机制来处理事件,而无需直接操作原生事件。
当使用 React 进行事件处理时,React 会利用事件代理机制来处理事件。事件代理是指将事件绑定到父元素上,然后通过冒泡机制将事件传递给子元素。这样做的好处是可以减少事件处理函数的数量,提高性能。

class ParentComponent extends React.Component {
  handleClick = (event) => {
    console.log('点击了子元素', event.target);
  }

  render() {
    return (
      <div onClick={this.handleClick}>
        <ChildComponent />
      </div>
    );
  }
}

class ChildComponent extends React.Component {
  render() {
    return <button>点击我</button>;
  }
}

在上面的例子中,ParentComponent 是父组件,ChildComponent 是子组件。当点击子组件中的按钮时,实际上是触发了父组件中的点击事件处理函数 handleClick。通过事件代理,我们可以在父组件中处理子组件的事件,这样可以更方便地管理和控制事件。

handleClick 函数中,我们可以通过 event.target 来获取触发事件的具体元素,这里就是子组件中的按钮。

需要注意的是,事件代理只对合成事件有效,而不适用于原生事件。因此,如果你需要在 React 中使用原生事件,需要使用 addEventListener 方法来手动绑定事件。文章来源地址https://www.toymoban.com/news/detail-604242.html

到了这里,关于【React】精选5题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端js react vue怎么实现在线预览doc文档

    先说结论: 目前在纯前端层面没有很好的方案,基本都需要服务端的介入。 优点 :简单易用,无需配置 缺点 :文档需要支持外网访问,且文档会是公开可见的,所以对于一些内部敏感的文档来说,这个显然是不可行的。 需要后端介入配合 onlyoffice地址 这个也要先在服务器

    2024年02月15日
    浏览(71)
  • 前端框架之争:Vue.js vs. React.js vs. Angular

    🎉欢迎来到Web前端专栏~前端框架之争:Vue.js vs. React.js vs. Angular ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹 ✨博客主页:IT·陈寒的博客 🎈该系列文章专栏:架构设计 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习 🍹文章作者技术和水平有限,如果

    2024年02月07日
    浏览(86)
  • Node.js npm V8 React Express的运行配合关系:构建JavaScript应用的基石

    目录 Node.js 和 V8 引擎 Node.js 和 npm LTS(Long Term Support) React Node.js的作用 Express Node.js 和 V8 引擎 Node.js 使用 Google 的 V8 JavaScript 引擎 来执行 JavaScript 代码。V8 是一个高性能的 JavaScript 和 WebAssembly 引擎,用于在 Google Chrome 浏览器和 Node.js 中运行 JavaScript。 V8 引擎的更新 通常包括

    2024年03月12日
    浏览(53)
  • 如何使用前端框架(React、Angular、Vue.js等)?该如何选择?

    聚沙成塔·每天进步一点点 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发者,这里都将为你提供一个系统而

    2024年02月07日
    浏览(50)
  • 【React】精选5题

    React 组件的生命周期可以分为三个阶段:挂载阶段、更新阶段和卸载阶段。每个生命周期方法都有特定的目的和功能。 挂载阶段: constructor:组件的构造函数,在组件被创建时调用,用于初始化状态和绑定方法。 static getDerivedStateFromProps:在组件实例化和每次接收新的 props

    2024年02月16日
    浏览(17)
  • 【React】精选10题

    React Hooks是React16.8版本中引入的新特性,它带来了许多便利。 更简单的状态管理 使用useState Hook可以在函数组件中方便地管理状态,避免了使用类组件时需要继承React.Component的繁琐操作。 避免使用类组件:函数式组件的书写方式更加简单、直观,避免了类组件中this指针的混乱

    2024年02月13日
    浏览(20)
  • 前端刷新页面的五种方法(含原生js、vue和react)

    1、window.history.go(0)方法 2、location.reload()方法 3、location.href=location.href方法 4、vue-router方法 5、react-router方法

    2024年02月16日
    浏览(41)
  • 【React】每日精选5题 2023-7-6

    可以使用JavaScript的typeof运算符和React的Component类来进行判断。 代码示例: 上面定义了一个名为isClassComponent的函数,它接受一个组件作为参数。函数内部使用typeof运算符来判断该组件是否为函数类型,并通过检查component.prototype.isReactComponent属性来确定是否为Class组件。 useRef、

    2024年02月13日
    浏览(28)
  • 【React】每日精选5题 2023-7-14

    React.memo() 和 JS 的 memorize 函数都是用来对函数进行结果缓存,提高函数的性能表现。不过,它们之间还是有一些区别的: 适用范围不同 :React.memo() 主要适用于优化 React 组件的性能表现,而 memorize 函数可以用于任何 JavaScript 函数的结果缓存。 实现方式不同 :React.memo() 是一

    2024年02月16日
    浏览(31)
  • 前端2023最全面试题(javaScript、typeScript、vue2、vue3、html、css、uniapp、webpack、vite、react)

    答案:JavaScript中的闭包是一种函数,它有权访问其词法环境的变量和其它函数。这意味着,即使其包含它的函数已经执行完毕,其词法环境仍然存在,因此可以访问其作用域内的变量。 答案:回调函数是在某个特定事件之后执行的函数。在JavaScript中,通常使用回调函数来处

    2024年02月06日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包