Recherche…


Remarques

React.createClass est React.createClass obsolète dans la version 15.5 et devrait être supprimé dans la version 16 . Il existe un package de remplacement pour ceux qui en ont encore besoin. Les exemples qui l’utilisent doivent être mis à jour.

Composant de base

Vu le fichier HTML suivant:

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>React Tutorial</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react-dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"></script>
  </head>
  <body>
    <div id="content"></div>
    <script type="text/babel" src="scripts/example.js"></script>
  </body>
</html>

Vous pouvez créer un composant de base en utilisant le code suivant dans un fichier distinct:

scripts / example.js

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class FirstComponent extends Component {
  render() {
    return (
      <div className="firstComponent">
        Hello, world! I am a FirstComponent.
      </div>
    );
  }
}
ReactDOM.render(
  <FirstComponent />, // Note that this is the same as the variable you stored above
  document.getElementById('content')
);

Vous obtiendrez le résultat suivant (notez le contenu de div#content ):

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>React Tutorial</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react-dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"></script>
  </head>
  <body>
    <div id="content">
        <div className="firstComponent">
            Hello, world! I am a FirstComponent.
        </div>
    </div>
    <script type="text/babel" src="scripts/example.js"></script>
  </body>
</html>

Composants d'imbrication

Une grande partie de la puissance de ReactJS réside dans sa capacité à permettre l’imbrication de composants. Prenez les deux composants suivants:

var React = require('react');
var createReactClass = require('create-react-class');

var CommentList = reactCreateClass({
  render: function() {
    return (
      <div className="commentList">
        Hello, world! I am a CommentList.
      </div>
    );
  }
});

var CommentForm = reactCreateClass({
  render: function() {
    return (
      <div className="commentForm">
        Hello, world! I am a CommentForm.
      </div>
    );
  }
});

Vous pouvez imbriquer et faire référence à ces composants dans la définition d'un composant différent:

var React = require('react');
var createReactClass = require('create-react-class');

var CommentBox = reactCreateClass({
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList /> // Which was defined above and can be reused
        <CommentForm /> // Same here
      </div>
    );
  }
});

La nidification supplémentaire peut être effectuée de trois manières différentes, qui ont toutes leur propre emplacement.

1. Nidification sans enfants

(suite de ci-dessus)

var CommentList = reactCreateClass({
  render: function() {
    return (
      <div className="commentList">
        <ListTitle/>
        Hello, world! I am a CommentList.
      </div>
    );
  }
});

C'est le style où A compose B et B compose C.

Avantages

  • Facile et rapide pour séparer les éléments de l'interface utilisateur
  • Facile à injecter des accessoires aux enfants en fonction de l'état du composant parent

Les inconvénients

  • Moins de visibilité sur l'architecture de composition
  • Moins de réutilisation

Bon si

  • B et C ne sont que des composants de présentation
  • B devrait être responsable du cycle de vie de C

2. Nidification à l'aide d'enfants

(suite de ci-dessus)

var CommentBox = reactCreateClass({
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList>
            <ListTitle/> // child
        </CommentList>
        <CommentForm />
      </div>
    );
  }
});

C'est le style où A compose B et A indique à B de composer C. Plus de puissance aux composants parents.

Avantages

  • Meilleure gestion du cycle de vie des composants
  • Meilleure visibilité dans l'architecture de composition
  • Meilleure réutilisabilité

Les inconvénients

  • L'injection d'accessoires peut devenir un peu cher
  • Moins de flexibilité et de puissance dans les composants enfants

Bon si

  • B devrait accepter de composer quelque chose de différent de C dans le futur ou ailleurs
  • A devrait contrôler le cycle de vie de C

B rendrait C en utilisant this.props.children , et B ne this.props.children aucune manière structurée de savoir à quoi servent ces enfants. Ainsi, B peut enrichir les composants enfants en donnant des accessoires supplémentaires, mais si B doit savoir exactement ce qu'ils sont, le n ° 3 pourrait être une meilleure option.

3. Nidification à l'aide d'accessoires

(suite de ci-dessus)

var CommentBox = reactCreateClass({
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList title={ListTitle}/> //prop
        <CommentForm />
      </div>
    );
  }
});

C'est le style où A compose B et B fournit une option permettant à A de passer quelque chose à composer dans un but spécifique. Composition plus structurée.

Avantages

  • Composition en tant que caractéristique
  • Validation facile
  • Meilleure composition

Les inconvénients

  • L'injection d'accessoires peut devenir un peu cher
  • Moins de flexibilité et de puissance dans les composants enfants

Bon si

  • B a des fonctionnalités spécifiques définies pour composer quelque chose
  • B ne devrait savoir que rendre que ne pas rendre

# 3 est généralement un must pour créer une bibliothèque publique de composants mais aussi une bonne pratique pour créer des composants composables et définir clairement les caractéristiques de la composition. # 1 est le plus simple et le plus rapide pour faire quelque chose qui fonctionne, mais # 2 et # 3 devraient offrir certains avantages dans divers cas d'utilisation.

Création de composants

Ceci est une extension de l'exemple de base:

Structure basique

import React, { Component } from 'react';
import { render } from 'react-dom';

class FirstComponent extends Component {
    render() {
        return (
            <div>
                Hello, {this.props.name}! I am a FirstComponent.
            </div>
        );
    }
}

render(
    <FirstComponent name={ 'User' } />,
    document.getElementById('content')
);

L'exemple ci-dessus est appelé un composant sans état car il ne contient pas d' état (au sens réactif du mot).

Dans un tel cas, certaines personnes trouvent préférable d'utiliser des composants fonctionnels sans état, basés sur des fonctions fléchées ES6 .

Composants fonctionnels sans état

Dans de nombreuses applications, il existe des composants intelligents contenant des états mais rendant des composants stupides qui reçoivent simplement des objets et renvoient du code HTML au format JSX. Les composants fonctionnels sans état sont beaucoup plus réutilisables et ont un impact positif sur les performances de votre application.

Ils ont 2 caractéristiques principales:

  1. Lorsqu'ils sont rendus, ils reçoivent un objet avec tous les accessoires qui ont été transmis
  2. Ils doivent retourner le JSX à rendre
// When using JSX inside a module you must import React
import React from 'react';
import PropTypes from 'prop-types';

const FirstComponent = props => (
    <div>
        Hello, {props.name}! I am a FirstComponent.
    </div>
);

//arrow components also may have props validation
FirstComponent.propTypes = {
    name: PropTypes.string.isRequired,
}

// To use FirstComponent in another file it must be exposed through an export call:
export default FirstComponent;

Composants avec état

Contrairement aux composants "sans état" présentés ci-dessus, les composants "avec état" ont un objet d'état qui peut être mis à jour avec la méthode setState . L'état doit être initialisé dans le constructor avant de pouvoir être défini:

import React, { Component } from 'react';

class SecondComponent extends Component {
    constructor(props) {
        super(props);

        this.state = {
            toggle: true
        };

        // This is to bind context when passing onClick as a callback
        this.onClick = this.onClick.bind(this);
    }

    onClick() {
        this.setState((prevState, props) => ({
            toggle: !prevState.toggle
        }));
    }
    
    render() {
        return (
            <div onClick={this.onClick}>
                Hello, {this.props.name}! I am a SecondComponent.
                <br />
                Toggle is: {this.state.toggle}
            </div>
        );
    }
}

L'extension d'un composant avec PureComponent au lieu de Component implémentera automatiquement la méthode du cycle de vie shouldComponentUpdate() avec une comparaison peu profonde des propriétés et des états. Cela permet à votre application d'être plus performante en réduisant la quantité de rendus inutiles. Cela suppose que vos composants sont «purs» et rendent toujours la même sortie avec le même état et la même entrée de propriétés.

Composants d'ordre supérieur

Les composants d'ordre supérieur (HOC) permettent de partager les fonctionnalités des composants.

import React, { Component } from 'react';

const PrintHello = ComposedComponent => class extends Component {
    onClick() {
        console.log('hello');
    }
    
    /* The higher order component takes another component as a parameter 
    and then renders it with additional props */
    render() {
        return <ComposedComponent {...this.props } onClick={this.onClick} />
    }
}

const FirstComponent = props => (
    <div onClick={ props.onClick }>
        Hello, {props.name}! I am a FirstComponent.
    </div>
);

const ExtendedComponent = PrintHello(FirstComponent);

Les composants d'ordre supérieur sont utilisés lorsque vous souhaitez partager la logique entre plusieurs composants, quelle que soit la différence de rendu.

setState pièges

Vous devez faire preuve de prudence lorsque vous utilisez setState dans un contexte asynchrone. Par exemple, vous pouvez essayer d'appeler setState dans le rappel d'une requête get:

class MyClass extends React.Component {
    constructor() {
        super();

        this.state = {
            user: {}
        };
    }

    componentDidMount() {
        this.fetchUser();
    }

    fetchUser() {
        $.get('/api/users/self')
            .then((user) => {
                this.setState({user: user});
            });
    }

    render() {
        return <h1>{this.state.user}</h1>;
    }
}

Cela pourrait appeler des problèmes - si le rappel est appelé après que le Component est démonté, alors this.setState ne sera pas une fonction. Chaque fois que c'est le cas, vous devez veiller à ce que votre utilisation de setState soit setState .

Dans cet exemple, vous pouvez annuler la demande XHR lorsque le composant est démonté:

class MyClass extends React.Component {
    constructor() {
        super();

        this.state = {
            user: {},
            xhr: null
        };
    }

    componentWillUnmount() {
        let xhr = this.state.xhr;

        // Cancel the xhr request, so the callback is never called
        if (xhr && xhr.readyState != 4) {
            xhr.abort();
        }
    }

    componentDidMount() {
        this.fetchUser();
    }

    fetchUser() {
        let xhr = $.get('/api/users/self')
            .then((user) => {
                this.setState({user: user});
            });

        this.setState({xhr: xhr});
    }
}

La méthode asynchrone est enregistrée en tant qu'état. Dans componentWillUnmount vous effectuez tout votre nettoyage, y compris l'annulation de la demande XHR.

Vous pourriez aussi faire quelque chose de plus complexe. Dans cet exemple, je crée une fonction 'stateSetter' qui accepte cet objet comme argument et empêche this.setState lorsque la fonction cancel a été appelée:

function stateSetter(context) {
    var cancelled = false;
    return {
        cancel: function () {
            cancelled = true;
        },
        setState(newState) {
            if (!cancelled) {
                context.setState(newState);
            }
        }
    }
}

class Component extends React.Component {
    constructor(props) {
        super(props);
        this.setter = stateSetter(this);
        this.state = {
            user: 'loading'
        };
    }
    componentWillUnmount() {
        this.setter.cancel();
    }
    componentDidMount() {
        this.fetchUser();
    }
    fetchUser() {
        $.get('/api/users/self')
            .then((user) => {
                this.setter.setState({user: user});
            });
    }
    render() {
        return <h1>{this.state.user}</h1>
    }
}

Cela fonctionne car la variable cancelled est visible dans la fermeture de setState nous avons créée.

Les accessoires

Les accessoires sont un moyen de transmettre des informations dans un composant React, ils peuvent avoir n'importe quel type, y compris des fonctions - parfois appelés rappels.

Dans JSX, les objets sont transmis avec la syntaxe d'attribut

<MyComponent userID={123} />

Dans la définition de MyComponent, userID sera désormais accessible depuis l'objet props

// The render function inside MyComponent
render() {
    return (
        <span>The user's ID is {this.props.userID}</span>
    )
}

Il est important de définir tous les props , leurs types et, le cas échéant, leur valeur par défaut:

// defined at the bottom of MyComponent
MyComponent.propTypes = {
    someObject: React.PropTypes.object,
    userID: React.PropTypes.number.isRequired,
    title: React.PropTypes.string
};

MyComponent.defaultProps = {
    someObject: {},
    title: 'My Default Title'
}

Dans cet exemple, le prop someObject est facultatif, mais l' userID prop est requis. Si vous ne parvenez pas à fournir userID à MyComponent , à l'exécution, le moteur React affiche une console vous avertissant que le prop requis n'a pas été fourni. Attention, cet avertissement ne s'affiche que dans la version de développement de la bibliothèque React, la version de production ne enregistrera aucun avertissement.

Utiliser defaultProps vous permet de simplifier

const { title = 'My Default Title' } = this.props;
console.log(title);

à

console.log(this.props.title);

C'est aussi une garantie pour l'utilisation du array object et des functions . Si vous ne fournissez pas de support par défaut pour un objet, les éléments suivants génèrent une erreur si le prop n'est pas transmis:

if (this.props.someObject.someKey)

Dans l'exemple ci-dessus, this.props.someObject n'est undefined et par conséquent, la vérification de someKey une erreur et le code sera rompu. Avec l'utilisation de defaultProps vous pouvez utiliser en toute sécurité la vérification ci-dessus.

Etats des composants - Interface utilisateur dynamique

Supposons que nous voulions avoir le comportement suivant - Nous avons un en-tête (par exemple un élément h3) et en cliquant dessus, nous voulons qu'il devienne une zone de saisie pour pouvoir modifier le nom de l'en-tête. React rend cela très simple et intuitif en utilisant les états des composants et si des instructions sont utilisées. (Explication du code ci-dessous)

// I have used ReactBootstrap elements. But the code works with regular html elements also
var Button = ReactBootstrap.Button;
var Form = ReactBootstrap.Form;
var FormGroup = ReactBootstrap.FormGroup;
var FormControl = ReactBootstrap.FormControl;

var Comment = reactCreateClass({
  getInitialState: function() {
    return {show: false, newTitle: ''};
  },

  handleTitleSubmit: function() {
     //code to handle input box submit - for example, issue an ajax request to change name in database
  },

  handleTitleChange: function(e) {
    //code to change the name in form input box. newTitle is initialized as empty string. We need to update it with the string currently entered by user in the form
    this.setState({newTitle: e.target.value});
  },

  changeComponent: function() {
    // this toggles the show variable which is used  for dynamic UI
    this.setState({show: !this.state.show)};
  },

  render: function() {

    var clickableTitle;

    if(this.state.show) {
        clickableTitle = <Form inline onSubmit={this.handleTitleSubmit}>
                             <FormGroup controlId="formInlineTitle">
                                 <FormControl type="text" onChange={this.handleTitleChange}>
                             </FormGroup>
                         </Form>;
    } else {
        clickabletitle = <div>
                            <Button bsStyle="link" onClick={this.changeComponent}>
                                <h3> Default Text </h3>
                            </Button>
                         </div>;
    }

    return (
        <div className="comment">
            {clickableTitle}
        </div>
    );
  }
});

ReactDOM.render(
    <Comment />, document.getElementById('content')
);

La partie principale du code est la variable clickableTitle . Basé sur la variable d'état show , il peut s'agir d'un élément Form ou d'un élément Button. React permet l'imbrication de composants.

Nous pouvons donc ajouter un élément {clickableTitle} dans la fonction de rendu. Il recherche la variable clickableTitle. Basé sur la valeur 'this.state.show', il affiche l'élément correspondant.

Variations de composants fonctionnels sans état

const languages = [
  'JavaScript',
  'Python',
  'Java',
  'Elm',
  'TypeScript',
  'C#',
  'F#'
]

// one liner
const Language = ({language}) => <li>{language}</li>

Language.propTypes = {
  message: React.PropTypes.string.isRequired
}

/**
* If there are more than one line.
* Please notice that round brackets are optional here,
* However it's better to use them for readability
*/
const LanguagesList = ({languages}) => {
  <ul>
    {languages.map(language => <Language language={language} />)}
  </ul>
}

LanguagesList.PropTypes = {
  languages: React.PropTypes.array.isRequired
}

/**
 * This syntax is used if there are more work beside just JSX presentation
 * For instance some data manipulations needs to be done.
 * Please notice that round brackets after return are required,
 * Otherwise return will return nothing (undefined)
 */
const LanguageSection = ({header, languages}) => {
  // do some work
  const formattedLanguages = languages.map(language => language.toUpperCase())
  return (
    <fieldset>
      <legend>{header}</legend>
      <LanguagesList languages={formattedLanguages} />
    </fieldset>
  )
}

LanguageSection.PropTypes = {
  header: React.PropTypes.string.isRequired,
  languages: React.PropTypes.array.isRequired
}

ReactDOM.render(
  <LanguageSection 
    header="Languages" 
    languages={languages} />,
  document.getElementById('app')
)

Ici vous pouvez trouver exemple de travail de celui - ci.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow