React总结

225 阅读10分钟
  • props和state的区别

   props是只读属性,不能被修改,是传递给组件的(类似于形参);state是在组件内被组件自己管理的(类似于在一个函数内声明的变量), 包含了随时可能发生变化的数据, 由用户自定义。

     如果某些值未用于渲染或数据流(例如,计时器 ID),则不必将其设置为 state,此类值可以在组件实例上定义。

  • 函数组件&&class组件&&Hook

    Hook是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及生命周期等特性。(只能在函数最外层调用 Hook;只能在 React 的函数组件中调用 Hook。)

    没有Hook时函数组件接收props作为参数,返回React组件,没有状态和生命周期方法。

     class组件使用ES6语法

     函数组件的性能比类组件的性能要高,因为类组件使用的时候要实例化,而函数组件直接执行函数取返回结果即可。

  • 什么是JSX

        JSX,是一个 JavaScript 的语法扩展。React 认为渲染逻辑本质上与其他 UI 逻辑内在耦合,比如,在 UI 中需要绑定处理事件、在某些时刻状态发生变化时需要通知到 UI,以及需要在 UI 中展示准备好的数据。

     React 并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式,而是通过将二者共同存放在称之为“组件”的松散耦合单元之中,来实现关注点分离。

  • setState

setState() 将对组件 state 的更改排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件。setState() 并不总是立即更新组件。它会批量推迟更新。请使用 componentDidUpdate 或者 setState 的回调函数(setState(updater, callback)),这两种方式都可以保证在应用更新后触发。

setState() 的第一个参数除了接受函数外,还可以接受对象类型

setState() 的第二个参数为可选的回调函数,它将在 setState 完成合并并重新渲染组件后执行。通常,我们建议使用 componentDidUpdate() 来代替此方式。

     如果后续状态取决于当前状态,我们建议使用 updater 函数的形式代替

  • 性能优化

  •    使用生产版本

  • shouldComponentUpdate或[React.PureComponent](https://zh-hans.reactjs.org/docs/react-api.html#reactpurecomponent)

  • key

      React更新列表时会顺序遍历元素,在子元素列表末尾新增元素时,更新开销比较小;如果只是简单的将新增元素插入到表头,那么更新开销会比较大。 

       当子元素拥有 key 时,React 使用 key 来匹配原有树上的子元素以及最新树上的子元素。

        组件实例是基于它们的 key 来决定是否更新以及复用,你也可以使用元素在数组中的下标作为 key。这个策略在元素不进行重新排序时比较合适,如果有顺序修改,diff 就会变得慢。

      key 帮助 React 识别出被修改、添加或删除的 item。应当给数组内的每个元素都设定 key,以使元素具有固定身份标识。

  • 高阶组件(HOC)(Higher-Order Component)

例如 Redux 的 [connect](https://github.com/reduxjs/react-redux/blob/master/docs/api/connect.md#connect)

我们需要一个抽象,允许我们在一个地方定义这个逻辑,并在许多组件之间共享它。这正是高阶组件擅长的地方。

请注意,HOC 不会修改传入的组件,也不会使用继承来复制其行为。相反,HOC 通过将组件

包装在容器组件中来组成新组件。HOC 是纯函数,没有副作用。

HOC 应该透传与自身无关的 props。

  • 虚拟DOM

Virtual DOM 是一种编程概念。在这个概念里, UI 以一种理想化的,或者说“虚拟的”表现形式被保存于内存中,并通过如 ReactDOM 等类库使之与“真实的” DOM 同步。

  • refs

     Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。
适用refs的情况:

  • 管理焦点,文本选择或媒体播放。
  • 触发强制动画。
  • 集成第三方 DOM 库。

   使用refs的两种方式

  • 使用 React.createRef() 创建,对该节点的引用可以在 ref 的 current 属性中被访问
  • 回调 refs:这个函数中接受 React 组件实例或 HTML DOM 元素作为参数,我们将其绑定到 this 指针以便在其他的类函数中使用。

      默认情况下,你不能在函数组件上使用 ref 属性,因为它们没有实例,但函数式组件同样能够利用闭包暂存其值。

      关于回调 refs 的说明:

      如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。

  • 生命周期

  • render

render() 方法是 class 组件中唯一必须实现的方法。

               render() 函数应该为纯函数,这意味着在不修改组件 state 的情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。

  • constructor

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

               通常,在 React 中,构造函数仅用于以下两种情况:

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

               你可以在 componentDidMount() 里直接调用 setState()。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在 render() 两次调用的情况下,用户也不会看到中间状态。如果你的渲染依赖于 DOM 节点的大小或位置,比如实现 modals 和 tooltips 等情况下,你可以使用此方式处理

  • componentDidUpdate

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

              你也可以在 componentDidUpdate() 中直接调用 setState(),但请注意它必须被包裹在一个条件语句里,正如上述的例子那样进行处理,否则会导致死循环。它还会导致额外的重新渲染,虽然用户不可见,但会影响组件性能。

  • componentWillUnmount

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

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

  • shouldComponentUpdate

              根据 shouldComponentUpdate() 的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。

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

  • static getDerivedStateFromProps

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

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

              此方法无权访问组件实例。不管原因是什么,都会在每次渲染前触发此方法。

  • getSnapshotBeforeUpdate

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

  • static getDerivedStateFromError

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

               getDerivedStateFromError() 会在渲染阶段调用,因此不允许出现副作用。 如遇此类情况,请改用 componentDidCatch()。

  • componentDidCatch

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

  1. error —— 抛出的错误。
  2. info —— 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息

               componentDidCatch() 会在“提交”阶段被调用,因此允许执行副作用。 它应该用于记录错误之类的情况

               如果 class 组件定义了生命周期方法 static getDerivedStateFromError() 或 componentDidCatch() 中的任何一个(或两者),它就成为了 Error boundaries。Error boundaries 是 React 组件,它会在其子组件树中的任何位置捕获 JavaScript 错误,并记录这些错误,展示降级 UI 而不是崩溃的组件树。Error boundaries 组件会捕获在渲染期间,在生命周期方法以及其整个树的构造函数中发生的错误。仅使用 Error boundaries 组件来从意外异常中恢复的情况;不要将它们用于流程控制。

  • context

Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。

Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。

Context 主要应用场景在于很多不同层级的组件需要访问同样一些的数据。

请谨慎使用,因为这会使得组件的复用性变差。

挂载在 class 上的 contextType 属性会被重赋值为一个由 React.createContext() 创建的 Context 对象。这能让你使用 this.context 来消费最近 Context 上的那个值。你可以在任何生命周期中访问到它,包括 render 函数中。

  • portals

典型用例是当父组件有 overflow: hidden 或 z-index 样式时,但你需要子组件能够在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框

  • 代码分割

对你的应用进行代码分割能够帮助你“懒加载”当前用户所需要的内容,能够显著地提高你的应用性能。尽管并没有减少应用整体的代码体积,但你可以避免加载用户永远不需要的代码,并在初始加载的时候减少所需加载的代码量。

动态import()语法

React.lazy 函数能让你像渲染常规组件一样处理动态引入(的组件)。React.lazy 接受一个函数,这个函数需要动态调用 import()。它必须返回一个 Promise,该 Promise 需要 resolve 一个 default export 的 React 组件。

然后应在 Suspense 组件中渲染 lazy 组件,如此使得我们可以使用在等待加载 lazy 组件时做优雅降级(如 loading 指示器等)。

fallback 属性接受任何在组件加载过程中你想展示的 React 元素。

代码分割可以基于路由。

  • 事件处理

React 元素的事件处理和 DOM 元素的很相似,但是有一点语法上的不同:

  • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
  • 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
  • 在 React 中另一个不同点是你不能通过返回 false 的方式阻止默认行为。你必须显式的使用 preventDefault 。