Maison > interface Web > js tutoriel > le corps du texte

Compréhension complète du cycle de vie de React (avec code)

不言
Libérer: 2019-04-03 10:05:56
avant
2715 Les gens l'ont consulté

Cet article vous apporte une compréhension complète du cycle de vie de React (avec code). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Le cycle de vie d'un composant React est divisé en trois parties : l'instanciation, l'existence et la destruction.

Phase d'instanciation

Lors du rendu côté client, ce qui suit est appelé en séquence

  • getDefaultProps( )
  • getInitialState()
  • componentWillMount()
  • render()
  • componentDidMount()

Serveur -rendu côté

  • getDefaultProps()
  • getInitialState()
  • componentWillMount()
  • render()

Remarque : componentDidMount() ne sera pas rendu côté serveur

getDefaultProps

Pour chaque instance de composant, cette méthode ne sera appelée qu'une seule fois ; et la classe de composants Dans toutes les applications ultérieures, getDefaultPops ne sera plus appelé et l'objet renvoyé peut être utilisé pour définir les valeurs des accessoires par défaut.

var Hello = React.creatClass({
    getDefaultProps: function(){
        return {
            name: 'pomy',
            git: 'dwqs'
        }
    },
    
    render: function(){
        return (
            <p>Hello,{this.props.name},git username is {this.props.dwqs}</p>
        )
    }
});

ReactDOM.render(<Hello />, document.body);
Copier après la connexion

Vous pouvez également définir des accessoires lors du montage du composant.

var data = [{title: 'Hello'}];
<Hello data={data} />
Copier après la connexion

Ou appelez setProps (généralement pas besoin d'appeler) pour définir ses accessoires

var data = [{title: 'Hello'}];
var Hello = React.render(<Demo />, document.body);
Hello.setProps({data:data});
Copier après la connexion

Mais setProps ne peut être appelé que sur des composants enfants ou des arborescences de composants. N'appelez pas this.setProps et ne modifiez pas this.props directement. Traitez-les comme des données en lecture seule.

React fournit un moyen de vérifier les accessoires via propTypes. propTypes est un objet de configuration utilisé pour définir les types de propriétés :

var survey = React.createClass({
    propTypes: {
        survey: React.PropTypes.shape({
            id: React.PropTypes.number.isRequired
        }).isRequired,
        onClick: React.PropTypes.func,
        name: React.PropTypes.string,
        score: React.PropTypes.array
        ...
    },
    
    //...
})
Copier après la connexion

ou

import React, { Component } from 'react'
import PropTypes from 'prop-types'

class BetterImage extends Component{...}

BetterImage.PropTypes={
  src: PropTypes.string,
  center: PropTypes.bool,
  loadingImage: PropTypes.string,
  defaultImage: PropTypes.string,
  onLoad: PropTypes.func,
  onError: PropTypes.func,
  onComplete: PropTypes.func
}
BetterImage.defaultProps={
  ....
}
Copier après la connexion

getInitialState

Pour chaque instance du composant, cette méthode est appelée une et une seule fois pour initialiser l'état de chaque instance. Dans cette méthode, vous pouvez accéder aux accessoires du composant. Chaque composant React a son propre état, qui diffère des accessoires dans la mesure où cet état n'existe qu'à l'intérieur du composant, tandis que les accessoires sont partagés entre toutes les instances.

Il existe une différence entre les appels de getInitialState et getDefaultPops. getDefaultPops n'est appelé qu'une seule fois pour la classe de composant, et les applications ultérieures de cette classe ne seront pas appelées, tandis que getInitialState est appelée pour chaque instance de composant, et. ne l'ajustez qu'une seule fois.

var LikeButton = React.createClass({
  //初始化State
  getInitialState: function() {
    return {liked: false};
  },
  
  handleClick: function(event) {
    //设置修改State
    this.setState({liked: !this.state.liked});
  },

  render: function() {
    var text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick}>
        You {text} this. Click to toggle.
      </p>
    );
  }
});

ReactDOM.render(
  <LikeButton />,
  document.getElementById('example')
);
Copier après la connexion

Chaque fois que l'état est modifié, le composant sera restitué. Après l'instanciation, le composant sera mis à jour via l'état et les méthodes suivantes seront appelées. séquence :

1、shouldComponentUpdate
2、componentWillUpdate
3、render
4、componentDidUpdate
Copier après la connexion
  • componentWillMount

est appelé avant le rendu, à la fois sur le client et sur le serveur. React a officiellement publié la version v16.3. Dans cette mise à jour, en plus de la nouvelle API Context qui a été vivement discutée il y a quelque temps, deux fonctions de cycle de vie nouvellement introduites getDerivedStateFromProps et getSnapshotBeforeUpdate et trois fonctions de cycle de vie ComponentWillMount seront supprimées dans la future version v17.0, composantWillReceiveProps, composantWillUpdate.

Dans ce cycle de vie, vous rencontrerez les problèmes suivants :

a. Aucune donnée sur le premier écran ne conduit à un écran blanc
Dans les applications React, de nombreux développeurs évitent l'écran blanc. En raison de l'absence de données asynchrones lors du premier rendu de la page, le code de la partie demande de données est placé dans composantWillMount, dans l'espoir d'éviter l'écran blanc et d'avancer le temps d'envoi des requêtes asynchrones. Mais en fait, après l'exécution de composantWillMount, le premier rendu a déjà commencé, donc si des données asynchrones n'ont pas été obtenues lors de l'exécution de composantWillMount, la page sera toujours dans un état sans données asynchrones lors de son premier rendu. En d’autres termes, le composant sera toujours dans un état sans données asynchrones lors de son premier rendu. Ainsi, quel que soit l’endroit où la demande de données est envoyée, il n’existe pas de solution directe à ce problème. Concernant l'envoi précoce des demandes de données, les responsables encouragent également à placer la partie du code de demande de données dans le constructeur du composant au lieu de composantWillMount.
S'il existe deux solutions qui ont été utilisées pour améliorer l'expérience utilisateur :

Méthode 1 : demander des composants de manière asynchrone, utilisez nprogress pour ajouter une animation de chargement

import React, { Component } from 'react'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import './customNprogress.styl'

NProgress.configure({ showSpinner: false })

export default function asyncComponent(importComponent) {
  class AsyncComponent extends Component {
    state = {
      component: null
    }

    async componentDidMount() {
      NProgress.start()
      const { default: component } = await importComponent()
      NProgress.done()

      this.setState({ component })
    }

    render() {
      const C = this.state.component

      return C ? <C {...this.props} /> : null
    }
  }

  return AsyncComponent
}

const AsyncNotFound = asyncComponent(() => import(/* webpackChunkName: "NotFound" */ '@/routes/NotFound'))
Copier après la connexion

Méthode 2 : Utiliser onreadystatechange écoute readyState et charge une page statique avec seulement un cadre avant la fin du chargement des ressources. La page ne demande pas de données. Lorsque la demande de données est terminée, l'itinéraire passe à la véritable page d'accueil.

  function listen () {
    if (document.readyState == 'complete') { // 资源加载完成
        ReactDom.render(
            <Provider store={store}>
                <Router>
                    <Route path="/" component={Index}/>
                </Router>
            </Provider>,
            document.getElementById('root')
        )
    } else { // 资源加载中
        ReactDom.render(
            <Provider store={store}>
                <Router>
                    <Route path="/" component={FirstScreen}/>
                </Router>
            </Provider>,
            document.getElementById('root')
        )
    }
}

document.onreadystatechange = listen
Copier après la connexion

Pour référence spécifique, veuillez vous référer à Résoudre le problème d'écran blanc de chargement de l'écran React First

b Abonnement à des événements

Un autre cas d'utilisation courant consiste à s'abonner à des événements. dans composantWillMount et annulez l'abonnement à l'événement correspondant dans composantWillUnmount. Mais en fait, React ne peut pas garantir qu'après l'appel de ComponentWillMount, ComponentWillUnmount du même composant sera également appelé. Un exemple de la version actuelle est que lors du rendu côté serveur, composantWillUnmount ne sera pas appelé côté serveur, donc l'abonnement aux événements dans composantWillMount provoquera directement une fuite de mémoire côté serveur. D'un autre côté, une fois que React aura activé le mode de rendu asynchrone à l'avenir, après l'appel de composantWillMount, le rendu du composant est susceptible d'être interrompu par d'autres transactions, ce qui empêchera l'appel de composantWillUnmount. **componentDidMount n'a pas ce problème. Après l'appel de ComponentDidMount, ComponentWillUnmount sera définitivement appelé par la suite et les abonnements aux événements existants dans le composant seront effacés en fonction du code spécifique. **

rendu

该方法会创建一个虚拟DOM,用来表示组件的输出。对于一个组件来讲,render方法是唯一一个必需的方法。render方法需要满足下面几点:

  • 只能通过 this.props 和 this.state 访问数据(不能修改)
  • 可以返回 null,false(这种场景下,react渲染一个
  • 只能出现一个顶级组件,不能返回一组元素
  • 不能改变组件的状态
  • 不能修改DOM的输出

render方法返回的结果并不是真正的DOM元素,而是一个虚拟的表现,类似于一个DOM tree的结构的对象。react之所以效率高,就是这个原因。

render执行情况如下:

1. 首次加载
2. setState改变组件内部state。
   注意: 此处是说通过setState方法改变。
3. 接受到新的props

注意:因为数据是异步的情况,会导致组件重复渲染

componentDidMount

该方法不会在服务端被渲染的过程中调用。该方法被调用时,已经渲染出真实的 DOM,可以再该方法中通过 this.getDOMNode() 访问到真实的 DOM(推荐使用 ReactDOM.findDOMNode())。

var data = [..];
var comp = React.createClass({
    render: function(){
        return <imput .. />
    },
    componentDidMount: function(){
        $(this.getDOMNode()).autoComplete({
            src: data
        })
    }
})
Copier après la connexion

由于组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性:

var Area = React.createClass({
    render: function(){
        this.getDOMNode(); //render调用时,组件未挂载,这里将报错
        
        return <canvas ref=&#39;mainCanvas&#39;>
    },
    componentDidMount: function(){
        var canvas = this.refs.mainCanvas.getDOMNode();
        //这是有效的,可以访问到 Canvas 节点
    }
})
Copier après la connexion

需要注意的是,由于 this.refs.[refName] 属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性,否则会报错。如果ref回调函数以inline函数的方式来指定,那么在组件更新的时候ref回调会被调用2次。第一次回调的时候传入的参数是null,而第二次的时候才真正的传入DOM节点

更多了解ref使用
从React官方文档看 refs 的使用和未来
获取真实dom,并获取dom css 三种方法

存在期

此时组件已经渲染好并且用户可以与它进行交互,比如鼠标点击,手指点按,或者其它的一些事件,导致应用状态的改变,你将会看到下面的方法依次被调用;

  1. componentWillReceiveProps()
  2. shouldComponentUpdate()
  3. componentWillUpdate()
  4. render()
  5. componentDidUpdate()

componentWillReceiveProps

当props发生变化时执行,初始化render时不执行,在这个回调函数里面,你可以根据属性的变化,通过调用this.setState()来更新你的组件状态,旧的属性还是可以通过this.props来获取,这里调用更新状态是安全的,并不会触发额外的render调用。

componentWillReceiveProps: function(nextProps){
    if(nextProps.checked !== undefined){
        this.setState({
            checked: nextProps.checked
        })
    }
}
Copier après la connexion

了解更多点击此处

shouldComponentUpdate

shouldComponentUpdate函数是重渲染时render()函数调用前被调用的函数,它接受两个参数:nextProps和nextState,分别表示下一个props和下一个state的值。并且,当函数返回false时候,阻止接下来的render()函数及后面的 componentWillUpdate,componentDidUpdate 方法的调用,阻止组件重渲染,而返回true时,组件照常重渲染。

了解更多点击此处--真的讲的好

componentWillUpdate

这个方法和 componentWillMount 类似,在组件接收到了新的 props 或者 state 即将进行重新渲染前,componentWillUpdate(object nextProps, object nextState) 会被调用,注意不要在此方面里再去更新 props 或者 state。

componentDidUpdate

这个方法和 componentDidMount 类似,在组件重新被渲染之后,componentDidUpdate(object prevProps, object prevState) 会被调用。可以在这里访问并修改 DOM。

销毁

componentWillUnmount

每当React使用完一个组件,这个组件必须从 DOM 中卸载后被销毁,此时 componentWillUnmout 会被执行,完成所有的清理和销毁工作,在 componentDidMount 中添加的任务都需要再该方法中撤销,如创建的定时器或事件监听器。

当再次装载组件时,以下方法会被依次调用:

1、getInitialState
2、componentWillMount
3、render
4、componentDidMount

React v.16生命周期

constructor(props) // 初始化参数

componentWillMount()

render() // 第一次渲染 

componentDidMount()

**当父组件向子组件传入props发生改变后,依次调用**

componentWillReceiveProps(nextProps)

shouldComponentUpdate(nextProps, nextState) 

componentWillUpdate()

render() //子组件更新渲染

componentDidUpdate()

**当组件自身state发生变化后**

componentWillUpdate()

render() //组件再次更新渲染

componentDidUpdate()


当组件卸载

componentWillUnmount()
Copier après la connexion

与低于React16版本的比较

  1. Le nouveau cycle de vie de React16 est obsolète : composantWillMount, composantWillReceiveProps, composantWillUpdate
  2. Ajout de getDerivedStateFromProps, getSnapshotBeforeUpdate pour remplacer les trois fonctions hook obsolètes (componentWillMount, composantWillReceivePorps, composantWillUpdate)
  3. React1 6 l'a fait ne supprime pas ces trois fonctions de hook, mais elles ne peuvent pas être mélangées avec les nouvelles fonctions de hook (getDerivedStateFromProps, getSnapshotBeforeUpdate). React17 supprimera ComponentWillMount, ComponentWillReceivePorps et ComponentWillUpdate
  4. a ajouté une nouvelle paire Gestion des erreurs (componentDidCatch)

[Recommandations associées :

tutoriel vidéo React]

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!

Étiquettes associées:
source:segmentfault.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal