>  기사  >  웹 프론트엔드  >  React16의 새로운 기능은 무엇입니까?

React16의 새로운 기능은 무엇입니까?

青灯夜游
青灯夜游원래의
2020-12-16 11:55:062689검색

react16의 새로운 기능: 1. 배열 및 문자열 반환 지원 3. createPortal 4. Fiber 6. Fragment 8. 후크 .

React16의 새로운 기능은 무엇입니까?

【관련 튜토리얼 권장 사항: React 비디오 튜토리얼

React v16.0

render는 배열 및 문자열 반환을 지원합니다.

// 不需要再将元素作为子元素装载到根元素下面
render() {
  return [
    <li/>1</li>,
    <li/>2</li>,
    <li/>3</li>,
  ];
}

오류 경계

React15가 런타임 중에 발생했습니다. 오류가 발생합니다 전체 React 구성 요소가 충돌하고 오류 메시지가 불분명하고 읽기 어렵습니다. React16은 보다 우아한 오류 처리 전략을 지원합니다. 구성 요소의 렌더링 또는 수명 주기 방법에서 오류가 발생하면 다른 구성 요소의 렌더링에 영향을 주지 않고 전체 구성 요소 구조가 루트 노드에서 언로드됩니다. 오류 최적화.

class ErrorBoundary extends React.Component {
  state = { hasError: false };

  componentDidCatch(error, info) {
    this.setState({ hasError: true });

    logErrorToMyService(error, info);
  }

  render() {
    if (this.state.hasError) {
      return <h1>数据错误</h1>;
    }
    
    return this.props.children;
  }
}

createPortal

createPortal의 출현은 문서 흐름에서 분리된 팝업 창, 대화 상자 및 기타 구성 요소 개발에 대한 편의성을 제공합니다. 이는 이전의 불안정한 API 불안정한_renderSubtreeIntoContainer를 대체하고 다음과 같은 코드 사용에서 호환될 수 있습니다. as:

const isReact16 = ReactDOM.createPortal !== undefined;

const getCreatePortal = () =>
  isReact16
    ? ReactDOM.createPortal
    : ReactDOM.unstable_renderSubtreeIntoContainer;

createPortal 사용 Dialog 구성 요소는 componentDidMount 및 componentDidUpdate와 같은 수명 주기 기능을 사용하지 않고도 빠르게 생성할 수 있습니다.

그리고 createPortal에서 렌더링된 DOM을 통해 포털 입구에서 이벤트가 버블링될 수 있습니다. 입구에 onDialogClick과 같은 이벤트가 있으면 createPortal의 DOM도 호출할 수 있습니다.

import React from 'react';
import { createPortal } from 'react-dom';

class Dialog extends React.Component {
  constructor() {
    super(props);

    this.node = document.createElement('div');
    document.body.appendChild(this.node);
  }

  render() {
    return createPortal(
      <div>
        {this.props.children}
      </div>,
      this.node
    );
  }
}

사용자 정의 DOM 속성 지원

이전 React 버전의 DOM은 HTML 및 SVG에서 지원하는 속성 이외의 속성을 인식하지 못했습니다. React16 버전에서는 모든 속성이 DOM 요소로 전달됩니다. 이 새로운 기능을 사용하면 사용 가능한 React DOM 속성의 화이트리스트를 제거할 수 있습니다. 저자는 이전에 DOM이 아닌 속성인 filter-react-dom-props를 필터링하는 방법을 작성했습니다. 16년이 지나면 이러한 방법은 더 이상 필요하지 않게 됩니다.

파일 크기 줄이기

React16은 Rollup을 사용하여 다양한 대상 형식에 대한 코드를 패키징합니다. 패키징 도구의 변경으로 인해 라이브러리 파일의 크기가 줄었습니다.

  • React 라이브러리 크기가 20.7kb(압축 후 6.9kb)에서 5.3kb(압축 후 2.2kb)로 감소
  • ReactDOM 라이브러리 크기가 141kb(압축 후 42.9kb)에서 103.7kb(압축 후 32.6kb)로 감소
  • React + ReactDOM 라이브러리 크기가 161.7kb(압축 후 49.8kb)에서 109kb(압축 후 43.8kb)로 감소했습니다.

Fiber

Fiber는 React 코어 알고리즘을 다시 구현하여 원래 동기 업데이트 프로세스를 조각화하고 Long을 방지합니다. -메인 스레드의 기간 차단은 애플리케이션 렌더링을 더 원활하게 만듭니다.

React16 이전에는 컴포넌트를 업데이트할 때 각 컴포넌트의 수명주기 함수가 호출되고 Virtual DOM이 계산 및 비교되며 DOM 트리가 업데이트됩니다. 이 전체 프로세스는 동기식으로 수행되며 중간에 중단될 수 없습니다. . 구성 요소가 상대적으로 크고 업데이트 작업에 오랜 시간이 걸리는 경우 브라우저의 유일한 메인 스레드가 구성 요소 업데이트 작업을 수행하고 사용자 입력이나 애니메이션 렌더링에 응답할 수 없게 되어 사용자 경험에 큰 영향을 미칩니다.

Fiber는 샤딩이라는 개념을 사용하여 긴 작업을 여러 개의 작은 조각으로 나눕니다. 각 작은 조각의 실행 시간은 매우 짧습니다. 각 작은 조각이 실행된 후 제어권은 담당 React 모듈로 반환됩니다. 작업 조정 긴급한 작업이 있으면 우선 순위를 정하고, 긴급한 작업이 없으면 계속 업데이트하세요. 그러면 다른 작업을 실행할 기회가 생기고 항상 유일한 스레드가 독점되지는 않습니다.

따라서 구성 요소가 업데이트되면 업데이트 작업이 완료되기 전에 우선 순위가 높은 다른 업데이트 프로세스에 의해 중단될 수 있으며, 우선 순위가 낮은 업데이트 작업이 먼저 처리됩니다. 귀하의 작업은 완전히 폐기되며 다시 시작할 수 있는 기회를 기다려야 합니다. 따라서 React Fiber는 업데이트 프로세스를 두 단계로 나눕니다.

  • 첫 번째 단계인 조정 단계에서는 Fiber가 업데이트해야 하는 DOM을 찾습니다. 이 단계는 중단될 수 있습니다.
  • 두 번째 단계인 커밋 단계에는 다음이 있습니다. 방해할 방법이 없으며 DOM의 업데이트 및 표시를 완료합니다.

Fiber를 사용한 후에는 여러 번 또는 반복되는 로직 호출을 피하기 위해 첫 번째 단계와 관련된 수명 주기 기능을 확인해야 합니다.

    shouldComponentUpdate
  • comComponentWillUpdate
  • 두 번째 단계와 관련된 수명주기 기능:
  • comComponentDidMount

comComponentDidUpdate

    comComponentWillUnmount
  • React v16.1

콜 리턴(react-call-return npm) react-call-return은 현재 독립적인 npm 패키지로, 주로 하위 구성 요소의 콜백 정보를 기반으로 하위 구성 요소 장면을 렌더링해야 하는 상위 구성 요소에 대한 솔루션을 제공합니다.

React16 이전에는 위 시나리오에 대해 일반적으로 두 가지 솔루션이 있었습니다.

  • 首先让子组件初始化渲染,通过回调函数把信息传给父组件,父组件完成处理后更新子组件 props,触发子组件的第二次渲染才可以解决,子组件需要经过两次渲染周期,可能会造成渲染的抖动或闪烁等问题;
  • 首先在父组件通过 children 获得子组件并读取其信息,利用 React.cloneElement 克隆产生新元素,并将新的属性传递进去,父组件 render 返回的是克隆产生的子元素。虽然这种方法只需要使用一个生命周期,但是父组件的代码编写会比较麻烦;

React16 支持的 react-call-return,提供了两个函数 unstable_createCall 和 unstable_createReturn,其中 unstable_createCall 是 父组件使用,unstable_createReturn 是 子组件使用,父组件发出 Call,子组件响应这个 Call,即 Return。

  • 在父组件 render 函数中返回对 unstable_createCall 的调用,第一个参数是 props.children,第二个参数是一个回调函数,用于接受子组件响应 Call 所返回的信息,第三个参数是 props;
  • 在子组件 render 函数返回对 unstable_createReturn 的调用,参数是一个对象,这个对象会在unstable_createCall 第二个回调函数参数中访问到;
  • 当父组件下的所有子组件都完成渲染周期后,由于子组件返回的是对 unstable_createReturn 的调用所以并没有渲染元素,unstable_createCall 的第二个回调函数参数会被调用,这个回调函数返回的是真正渲染子组件的元素;

针对普通场景来说,react-call-return 有点过度设计的感觉,但是如果针对一些特定场景的话,它的作用还是非常明显,比如,在渲染瀑布流布局时,利用 react-call-return 可以先缓存子组件的 ReactElement,等必要的信息足够之后父组件再触发 render,完成渲染。

import React from 'react';
import { unstable_createReturn, unstable_createCall } from 'react-call-return';

const Child = (props) => {
  return unstable_createReturn({
    size: props.children.length,
    renderItem: (partSize, totalSize) => {
      return <div>{ props.children } { partSize } / { totalSize }</div>;
    }
  });
};

const Parent = (props) => {
  return (
    <div>
      {
        unstable_createCall(
          props.children,
          (props, returnValues) => {
            const totalSize = returnValues.map(v => v.size).reduce((a, b) => a + b, 0);
            return returnValues.map(({ size, renderItem }) => {
              return renderItem(size, totalSize);
            });
          },
          props
        )
      }
    </div>
  );
};

React v16.2

Fragment

Fragment 组件其作用是可以将一些子元素添加到 DOM tree 上且不需要为这些元素提供额外的父节点,相当于 render 返回数组元素。

render() {
  return (
    <Fragment>
      Some text.
      <h2>A heading</h2>
      More text.
      <h2>Another heading</h2>
      Even more text.
    </Fragment>
  );
}

React v16.3

createContext

全新的 Context API 可以很容易穿透组件而无副作用,其包含三部分:React.createContext,Provider,Consumer。

  • React.createContext 是一个函数,它接收初始值并返回带有 Provider 和 Consumer 组件的对象;
  • Provider 组件是数据的发布方,一般在组件树的上层并接收一个数据的初始值;
  • Consumer 组件是数据的订阅方,它的 props.children 是一个函数,接收被发布的数据,并且返回 React Element;
const ThemeContext = React.createContext('light');

class ThemeProvider extends React.Component {
  state = {theme: 'light'};

  render() {
    return (
      <ThemeContext.Provider value={this.state.theme}>
        {this.props.children}
      </ThemeContext.Provider>
    );
  }
}

class ThemedButton extends React.Component {
  render() {
    return (
      <ThemeContext.Consumer>
        {theme => <Button theme={theme} />}
      </ThemeContext.Consumer>
    );
  }
}

createRef / forwardRef

React16 规范了 Ref 的获取方式,通过 React.createRef 取得 Ref 对象。

// before React 16
···

  componentDidMount() {
    const el = this.refs.myRef
  }

  render() {
    return <div ref="myRef" />
  }

···

// React 16+
  constructor(props) {
    super(props)
    
    this.myRef = React.createRef()
  }

  render() {
    return <div ref={this.myRef} />
  }
···

React.forwardRef 是 Ref 的转发, 它能够让父组件访问到子组件的 Ref,从而操作子组件的 DOM。 React.forwardRef 接收一个函数,函数参数有 props 和 ref。

const TextInput = React.forwardRef((props, ref) => (
  <input type="text" placeholder="Hello forwardRef" ref={ref} />
))

const inputRef = React.createRef()

class App extends Component {
  constructor(props) {
    super(props)
    
    this.myRef = React.createRef()
  }

  handleSubmit = event => {
    event.preventDefault()
    
    alert('input value is:' + inputRef.current.value)
  }
  
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <TextInput ref={inputRef} />
        <button type="submit">Submit</button>
      </form>
    )
  }
}

生命周期函数的更新

React16 采用了新的内核架构 Fiber,Fiber 将组件更新分为两个阶段:Render Parse 和 Commit Parse,因此 React 也引入了 getDerivedStateFromProps 、 getSnapshotBeforeUpdate 及 componentDidCatch 等三个全新的生命周期函数。同时也将 componentWillMount、componentWillReceiveProps 和 componentWillUpdate 标记为不安全的方法。

static getDerivedStateFromProps(nextProps, prevState)

getDerivedStateFromProps(nextProps, prevState) 其作用是根据传递的 props 来更新 state。它的一大特点是无副作用,由于处在 Render Phase 阶段,所以在每次的更新都会触发该函数, 在 API 设计上采用了静态方法,使其无法访问实例、无法通过 ref 访问到 DOM 对象等,保证了该函数的纯粹高效。

为了配合未来的 React 异步渲染机制,React v16.4 对 getDerivedStateFromProps 做了一些改变, 使其不仅在 props 更新时会被调用,setState 时也会被触发。

  • 如果改变 props 的同时,有副作用的产生,这时应该使用 componentDidUpdate;
  • 如果想要根据 props 计算属性,应该考虑将结果 memoization 化;
  • 如果想要根据 props 变化来重置某些状态,应该考虑使用受控组件;
static getDerivedStateFromProps(props, state) {
  if (props.value !== state.controlledValue) {
    return {
      controlledValue: props.value,
    };
  }
  
  return null;
}

getSnapshotBeforeUpdate(prevProps, prevState)

getSnapshotBeforeUpdate(prevProps, prevState) 会在组件更新之前获取一个 snapshot,并可以将计算得的值或从 DOM 得到的信息传递到 componentDidUpdate(prevProps, prevState, snapshot) 函数的第三个参数,常常用于 scroll 位置定位等场景。

componentDidCatch(error, info)

componentDidCatch 函数让开发者可以自主处理错误信息,诸如错误展示,上报错误等,用户可以创建自己的 Error Boundary 来捕获错误。

componentWillMount(nextProps, nextState)

componentWillMount 被标记为不安全,因为在 componentWillMount 中获取异步数据或进行事件订阅等操作会产生一些问题,比如无法保证在 componentWillUnmount 中取消掉相应的事件订阅,或者导致多次重复获取异步数据等问题。

componentWillReceiveProps(nextProps) / componentWillUpdate(nextProps, nextState)

componentWillReceiveProps / componentWillUpdate 被标记为不安全,主要是因为操作 props 引起的 re-render 问题,并且对 DOM 的更新操作也可能导致重新渲染。

Strict Mode

StrictMode 可以在开发阶段开启严格模式,发现应用存在的潜在问题,提升应用的健壮性,其主要能检测下列问题:

  • 识别被标志位不安全的生命周期函数
  • 对弃用的 API 进行警告
  • 探测某些产生副作用的方法
  • 检测是否使用 findDOMNode
  • 检测是否采用了老的 Context API
class App extends React.Component {
  render() {
    return (
      <div>
        <React.StrictMode>
          <ComponentA />
        </React.StrictMode>
      </div>
    )
  }
}

React v16.4

Pointer Events

指针事件是为指针设备触发的 DOM 事件。它们旨在创建单个 DOM 事件模型来处理指向输入设备,例如鼠标,笔 / 触控笔或触摸(例如一个或多个手指)。指针是一个与硬件无关的设备,可以定位一组特定的屏幕坐标。拥有指针的单个事件模型可以简化创建 Web 站点和应用程序,并提供良好的用户体验,无论用户的硬件如何。但是,对于需要特定于设备的处理的场景,指针事件定义了一个 pointerType 属性,用于检查产生事件的设备类型。

React 新增 onPointerDown / onPointerMove / onPointerUp / onPointerCancel / onGotPointerCapture / onLostPointerCapture / onPointerEnter / onPointerLeave / onPointerOver / onPointerOut 等指针事件。

这些事件只能在支持 指针事件 规范的浏览器中工作。如果应用程序依赖于指针事件,建议使用第三方指针事件 polyfill。

React v16.5

Profiler

React 16.5 添加了对新的 profiler DevTools 插件的支持。这个插件使用 React 的 Profiler 实验性 API 去收集所有 component 的渲染时间,目的是为了找出 React App 的性能瓶颈,它将会和 React 即将发布的 时间片 特性完全兼容。

React v16.6

memo

React.memo() 只能作用在简单的函数组件上,本质是一个高阶函数,可以自动帮助组件执行shouldComponentUpdate(),但只是执行浅比较,其意义和价值有限。

const MemoizedComponent = React.memo(props => {
  /* 只在 props 更改的时候才会重新渲染 */
});

lazy / Suspense

React.lazy() 提供了动态 import 组件的能力,实现代码分割。

Suspense 作用是在等待组件时 suspend(暂停)渲染,并显示加载标识。

目前 React v16.6 中 Suspense 只支持一个场景,即使用 React.lazy() 和 实现的动态加载组件。

import React, {lazy, Suspense} from 'react';
const OtherComponent = lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <OtherComponent />
    </Suspense>
  );
}

static contextType

static contextType 为 Context API 提供了更加便捷的使用体验,可以通过 this.context 来访问 Context。

const MyContext = React.createContext();

class MyClass extends React.Component {
  static contextType = MyContext;
  
  componentDidMount() {
    const value = this.context;
  }
  
  componentDidUpdate() {
    const value = this.context;
  }
  
  componentWillUnmount() {
    const value = this.context;
  }
  
  render() {
    const value = this.context;
  }
}

getDerivedStateFromError

static getDerivedStateFromError(error) 允许开发者在 render 完成之前渲染 Fallback UI,该生命周期函数触发的条件是子组件抛出错误,getDerivedStateFromError 接收到这个错误参数后更新 state。

class ErrorBoundary extends React.Component {
  state = { hasError: false };
  
  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }
  
  componentDidCatch(error, info) {
    // You can also log the error to an error reporting service
    logErrorToMyService(error, info);
  }
  
  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }
    
    return this.props.children; 
  }
}

React v16.7

Hooks

Hooks 要解决的是状态逻辑复用问题,且不会产生 JSX 嵌套地狱,其特性如下:

  • 多个状态不会产生嵌套,依然是平铺写法;
  • Hooks 可以引用其他 Hooks;
  • 更容易将组件的 UI 与状态分离;

Hooks 并不是通过 Proxy 或者 getters 实现,而是通过数组实现,每次 useState 都会改变下标,如果 useState 被包裹在 condition 中,那每次执行的下标就可能对不上,导致 useState 导出的 setter 更新错数据。

function App() {
  const [open, setOpen] = useState(false);
  
  return (
    <>
      <Button type="primary" onClick={() => setOpen(true)}>
        Open Modal
      </Button>
      <Modal
        visible={open}
        onOk={() => setOpen(false)}
        onCancel={() => setOpen(false)}
      />
    </>
  );
}

React v16.8

Concurrent Rendering

Concurrent Rendering 并发渲染模式是在不阻塞主线程的情况下渲染组件树,使 React 应用响应性更流畅,它允许 React 中断耗时的渲染,去处理高优先级的事件,如用户输入等,还能在高速连接时跳过不必要的加载状态,用以改善 Suspense 的用户体验。

目前 Concurrent Rendering 尚未正式发布,也没有详细相关文档,需要等待 React 团队的正式发布。

React v16.9

Suspense for Data Fetching

Suspense 通过 ComponentDidCatch 实现用同步的方式编写异步数据的请求,并且没有使用 yield / async / await,其流程:调用 render 函数 -> 发现有异步请求 -> 暂停渲染,等待异步请求结果 -> 渲染展示数据。

无论是什么异常,JavaScript 都能捕获,React就是利用了这个语言特性,通过 ComponentDidCatch 捕获了所有生命周期函数、render函数等,以及事件回调中的错误。如果有缓存则读取缓存数据,如果没有缓存,则会抛出一个异常 promise,利用异常做逻辑流控制是一种拥有较深的调用堆栈时的手段,它是在虚拟 DOM 渲染层做的暂停拦截,代码可在服务端复用。

import { fetchMovieDetails } from '../api';
import { createFetch } from '../future';

const movieDetailsFetch = createFetch(fetchMovieDetails);

function MovieDetails(props) {
  const movie = movieDetailsFetch.read(props.id);

  return (
    <div>
      <MoviePoster src={movie.poster} />
      <MovieMetrics {...movie} />
    </div>
  );
}

更多编程相关知识,请访问:编程课程!!

위 내용은 React16의 새로운 기능은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.