Nouvelles fonctionnalités de React16 : 1. render prend en charge le retour des tableaux et des chaînes ; 2. limites d'erreur ; 3. createPortal ; 4. prend en charge les attributs DOM personnalisés ; Crochets, etc
[Recommandations de didacticiel associées : Tutoriel vidéo React]
React v16.0
// 不需要再将元素作为子元素装载到根元素下面 render() { return [ <li/>1</li>, <li/>2</li>, <li/>3</li>, ]; }
React15 rencontre une erreur d'exécution pendant le processus de rendu, ce qui entraînera l'ensemble du composant React plante et le message d’erreur n’est pas clair et mal lisible. React16 prend en charge une stratégie de gestion des erreurs plus élégante. Si une erreur est générée dans la méthode de rendu ou de cycle de vie du composant, la structure entière du composant sera déchargée du nœud racine sans affecter le rendu des autres composants. Vous pouvez utiliser les limites d'erreur Effectuer. optimisation des erreurs.
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; } }
L'émergence de createPortal facilite le développement de fenêtres contextuelles, de boîtes de dialogue et d'autres composants séparés du flux de documents. Il remplace l'API instable précédente unstable_renderSubtreeIntoContainer et. peut être compatible dans l'utilisation du code. , tels que :
const isReact16 = ReactDOM.createPortal !== undefined; const getCreatePortal = () => isReact16 ? ReactDOM.createPortal : ReactDOM.unstable_renderSubtreeIntoContainer;
Utilisez createPortal pour créer rapidement des composants Dialog sans impliquer composantDidMount, composantDidUpdate et d'autres fonctions de cycle de vie.
Et grâce au DOM rendu par createPortal, des événements peuvent surgir depuis l'entrée du portail. S'il y a des événements tels que onDialogClick à l'entrée, le DOM dans createPortal peut également être appelé.
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 ); } }
Les versions précédentes de React du DOM ne reconnaissaient pas les attributs autres que ceux pris en charge par HTML et SVG. Dans la version React16, tous les attributs seront transmis aux éléments DOM. Cette nouvelle fonctionnalité nous permet de nous débarrasser de la liste blanche des propriétés React DOM disponibles. L'auteur a déjà écrit une méthode de filtrage des attributs non-DOM filter-react-dom-props Après 16 ans, une telle méthode ne sera plus nécessaire.
React16 utilise Rollup pour empaqueter le code pour différents formats cibles En raison des modifications apportées aux outils d'empaquetage, la taille des fichiers de bibliothèque a été réduite.
Fiber est une réimplémentation de l'algorithme de base de React, qui fragmente le processus de mise à jour synchrone d'origine pour éviter le blocage à long terme du thread principal et rendre le rendu de l'application plus fluide.
Avant React16, lors de la mise à jour d'un composant, la fonction de cycle de vie de chaque composant était appelée, le DOM virtuel était calculé et comparé, l'arborescence DOM était mise à jour, etc. Tout ce processus était réalisé de manière synchrone et ne pouvait pas être interrompu à mi-chemin. Lorsque le composant est relativement volumineux et que l'opération de mise à jour prend beaucoup de temps, le seul thread principal du navigateur effectuera les opérations de mise à jour des composants et sera incapable de répondre aux entrées de l'utilisateur ou au rendu de l'animation, ce qui affecte grandement l'expérience utilisateur.
Fiber utilise l'idée du sharding pour diviser une longue tâche en plusieurs petits morceaux. Le temps d'exécution de chaque petit morceau est très court. Une fois chaque petit morceau exécuté, le contrôle est renvoyé à React. pour la coordination des tâches, s'il y a des tâches urgentes, elles seront traitées en premier, sinon elles continueront à être mises à jour. Cela donnera une chance à d'autres tâches de s'exécuter, et le seul thread ne sera pas exclusif tout le temps.
Par conséquent, lors de la mise à jour d'un composant, il est possible qu'une tâche de mise à jour soit interrompue par un autre processus de mise à jour avec une priorité plus élevée avant qu'elle ne soit terminée. La tâche de mise à jour avec une priorité plus élevée sera traitée en premier, et la mise à jour. la tâche avec une priorité inférieure sera traitée en premier. Le travail effectué par la tâche de mise à jour sera complètement annulé et vous devrez attendre l'opportunité de recommencer. Ainsi, React Fiber divise un processus de mise à jour en deux phases :
React v16 .1
Call Return (react-call-return npm) react-call-return est actuellement un package npm indépendant, principalement pour les composants parents. utilisé pour restituer la solution fournie par la scène du sous-composant. Avant React16, il existait généralement deux solutions pour les scénarios ci-dessus :React16 支持的 react-call-return,提供了两个函数 unstable_createCall 和 unstable_createReturn,其中 unstable_createCall 是 父组件使用,unstable_createReturn 是 子组件使用,父组件发出 Call,子组件响应这个 Call,即 Return。
针对普通场景来说,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 组件其作用是可以将一些子元素添加到 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
全新的 Context API 可以很容易穿透组件而无副作用,其包含三部分:React.createContext,Provider,Consumer。
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> ); } }
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 标记为不安全的方法。
getDerivedStateFromProps(nextProps, prevState) 其作用是根据传递的 props 来更新 state。它的一大特点是无副作用,由于处在 Render Phase 阶段,所以在每次的更新都会触发该函数, 在 API 设计上采用了静态方法,使其无法访问实例、无法通过 ref 访问到 DOM 对象等,保证了该函数的纯粹高效。
为了配合未来的 React 异步渲染机制,React v16.4 对 getDerivedStateFromProps 做了一些改变, 使其不仅在 props 更新时会被调用,setState 时也会被触发。
static getDerivedStateFromProps(props, state) { if (props.value !== state.controlledValue) { return { controlledValue: props.value, }; } return null; }
getSnapshotBeforeUpdate(prevProps, prevState) 会在组件更新之前获取一个 snapshot,并可以将计算得的值或从 DOM 得到的信息传递到 componentDidUpdate(prevProps, prevState, snapshot) 函数的第三个参数,常常用于 scroll 位置定位等场景。
componentDidCatch 函数让开发者可以自主处理错误信息,诸如错误展示,上报错误等,用户可以创建自己的 Error Boundary 来捕获错误。
componentWillMount 被标记为不安全,因为在 componentWillMount 中获取异步数据或进行事件订阅等操作会产生一些问题,比如无法保证在 componentWillUnmount 中取消掉相应的事件订阅,或者导致多次重复获取异步数据等问题。
componentWillReceiveProps / componentWillUpdate 被标记为不安全,主要是因为操作 props 引起的 re-render 问题,并且对 DOM 的更新操作也可能导致重新渲染。
StrictMode 可以在开发阶段开启严格模式,发现应用存在的潜在问题,提升应用的健壮性,其主要能检测下列问题:
class App extends React.Component { render() { return ( <div> <React.StrictMode> <ComponentA /> </React.StrictMode> </div> ) } }
React v16.4
指针事件是为指针设备触发的 DOM 事件。它们旨在创建单个 DOM 事件模型来处理指向输入设备,例如鼠标,笔 / 触控笔或触摸(例如一个或多个手指)。指针是一个与硬件无关的设备,可以定位一组特定的屏幕坐标。拥有指针的单个事件模型可以简化创建 Web 站点和应用程序,并提供良好的用户体验,无论用户的硬件如何。但是,对于需要特定于设备的处理的场景,指针事件定义了一个 pointerType 属性,用于检查产生事件的设备类型。
React 新增 onPointerDown / onPointerMove / onPointerUp / onPointerCancel / onGotPointerCapture / onLostPointerCapture / onPointerEnter / onPointerLeave / onPointerOver / onPointerOut 等指针事件。
这些事件只能在支持 指针事件 规范的浏览器中工作。如果应用程序依赖于指针事件,建议使用第三方指针事件 polyfill。
React v16.5
React 16.5 添加了对新的 profiler DevTools 插件的支持。这个插件使用 React 的 Profiler 实验性 API 去收集所有 component 的渲染时间,目的是为了找出 React App 的性能瓶颈,它将会和 React 即将发布的 时间片 特性完全兼容。
React v16.6
React.memo() 只能作用在简单的函数组件上,本质是一个高阶函数,可以自动帮助组件执行shouldComponentUpdate(),但只是执行浅比较,其意义和价值有限。
const MemoizedComponent = React.memo(props => { /* 只在 props 更改的时候才会重新渲染 */ });
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 为 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; } }
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 要解决的是状态逻辑复用问题,且不会产生 JSX 嵌套地狱,其特性如下:
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 并发渲染模式是在不阻塞主线程的情况下渲染组件树,使 React 应用响应性更流畅,它允许 React 中断耗时的渲染,去处理高优先级的事件,如用户输入等,还能在高速连接时跳过不必要的加载状态,用以改善 Suspense 的用户体验。
目前 Concurrent Rendering 尚未正式发布,也没有详细相关文档,需要等待 React 团队的正式发布。
React v16.9
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> ); }
更多编程相关知识,请访问:编程课程!!
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!