Maison  >  Article  >  interface Web  >  Explication détaillée de l'utilisation des composants React

Explication détaillée de l'utilisation des composants React

php中世界最好的语言
php中世界最好的语言original
2018-03-27 15:49:251601parcourir

Cette fois je vais vous apporter une explication détaillée de l'utilisation des composants React, et quelles sont les précautions d'utilisation des composants React. Voici des cas pratiques, jetons un oeil. .

Quand j'ai commencé à écrire React, j'ai vu de nombreuses façons d'écrire des composants. Il existe cent façons d’écrire une centaine de tutoriels. Bien que React lui-même ait mûri, il ne semble pas y avoir de « bonne » façon de l’utiliser. Je (l'auteur) résume donc ici l'expérience d'utilisation de React que notre équipe a accumulée au fil des années. J'espère que cet article vous sera utile, que vous soyez débutant ou vétéran.

Avant de commencer :

Nous utilisons la syntaxe ES6 et ES7. Si vous n'êtes pas très clair sur la différence entre les composants d'affichage et les composants de conteneur, il est recommandé de commencer par lire cet article. Si vous avez des suggestions ou des questions, Duqing a laissé un message dans les commentaires sur les composants basés sur les classes

De nos jours, les composants React sont généralement développés à l'aide de composants basés sur les classes. Ensuite, nous écrirons notre composant sur la même ligne :

import React, { Component } from 'react';
import { observer } from 'mobx-react';
import ExpandableForm from './ExpandableForm';
import './styles/ProfileContainer.css';

J'aime le CSS en javascript. Cependant, cette méthode d’écriture des styles est encore trop nouvelle. Nous introduisons donc des fichiers CSS dans chaque composant. De plus, les importations introduites localement et les importations mondiales seront séparées par une ligne vide.

Initialiser l'état

import React, { Component } from 'react'
import { observer } from 'mobx-react'
import ExpandableForm from './ExpandableForm'
import './styles/ProfileContainer.css'
export default class ProfileContainer extends Component {
 state = { expanded: false }

Vous pouvez utiliser l'ancienne méthode pour initialiser constructor dans state. Des informations complémentaires peuvent être trouvées ici. Mais nous choisissons une approche plus claire.

De plus, nous avons veillé à ajouter export default devant la classe. (Note du traducteur : bien que cela puisse ne pas être correct lors de l'utilisation de Redux).

propTypes et defaultProps

import React, { Component } from 'react'
import { observer } from 'mobx-react'
import { string, object } from 'prop-types'
import ExpandableForm from './ExpandableForm'
import './styles/ProfileContainer.css'
export default class ProfileContainer extends Component {
 state = { expanded: false }
 
 static propTypes = {
  model: object.isRequired,
  title: string
 }
 
 static defaultProps = {
  model: {
   id: 0
  },
  title: 'Your Name'
 }
 // ...
}

propTypes et defaultProps sont des propriétés statiques. Définissez-le le plus tôt possible dans la classe du composant afin que les autres développeurs puissent le remarquer immédiatement lors de la lecture du code. Ils peuvent servir de documentation.

Si vous utilisez React 15.3.0 ou une version ultérieure, vous devez importer le package prop-types séparément au lieu d'utiliser React.PropTypes. Plus de contenu se déplace ici.

Tous vos composants doivent avoir des types d'accessoires.

Méthodes

import React, { Component } from 'react'
import { observer } from 'mobx-react'
import { string, object } from 'prop-types'
import ExpandableForm from './ExpandableForm'
import './styles/ProfileContainer.css'
export default class ProfileContainer extends Component {
 state = { expanded: false }
 
 static propTypes = {
  model: object.isRequired,
  title: string
 }
 
 static defaultProps = {
  model: {
   id: 0
  },
  title: 'Your Name'
 }
 handleSubmit = (e) => {
  e.preventDefault()
  this.props.model.save()
 }
 
 handleNameChange = (e) => {
  this.props.model.changeName(e.target.value)
 }
 
 handleExpand = (e) => {
  e.preventDefault()
  this.setState({ expanded: !this.state.expanded })
 }
 // ...
}

Dans les composants de classe, lorsque vous transmettez des méthodes aux composants enfants, vous devez vous assurer qu'ils sont appelés en utilisant le bon this. Cela se fait généralement lors du passage à un composant enfant : this.handleSubmit.bind(this).

Il est beaucoup plus simple d’utiliser la méthode des flèches d’ES6. Il maintient automatiquement le contexte correct (this).

Passez une méthode à setState

Dans l'exemple ci-dessus, il y a cette ligne :

this.setState({ expanded: !this.state.expanded });

setStateC'est en fait asynchrone ! Afin d'améliorer les performances, React appellera plusieurs setState ensemble. Par conséquent, l'état ne change pas nécessairement immédiatement après l'appel de setState.

Ainsi, lorsque vous appelez setState, vous ne pouvez pas vous fier à la valeur de l'état actuel. Parce que je ne connais pas du tout sa valeur.

Solution : Passez une méthode à setState et transmettez la valeur de l'état avant d'appeler en paramètre cette méthode. Jetez un œil à l'exemple :

this.setState(prevState => ({ expanded: !prevState.expanded }))

Merci à Austin Wood pour l'aide.

Démonter les composants

import React, { Component } from 'react'
import { observer } from 'mobx-react'
import { string, object } from 'prop-types'
import ExpandableForm from './ExpandableForm'
import './styles/ProfileContainer.css'
export default class ProfileContainer extends Component {
 state = { expanded: false }
 
 static propTypes = {
  model: object.isRequired,
  title: string
 }
 
 static defaultProps = {
  model: {
   id: 0
  },
  title: 'Your Name'
 }
 handleSubmit = (e) => {
  e.preventDefault()
  this.props.model.save()
 }
 
 handleNameChange = (e) => {
  this.props.model.changeName(e.target.value)
 }
 
 handleExpand = (e) => {
  e.preventDefault()
  this.setState(prevState => ({ expanded: !prevState.expanded }))
 }
 
 render() {
  const {
   model,
   title
  } = this.props
  return ( 
   
    

     

{title}

          

   
  )  } }

Pour les multi-lignes props, chaque accessoire doit occuper une ligne distincte. Tout comme l'exemple ci-dessus. La meilleure façon d'y parvenir est d'utiliser un ensemble d'outils : Prettier.

Decorator

@observer
export default class ProfileContainer extends Component {

Si vous connaissez certaines bibliothèques, telles que mobx, vous pouvez utiliser l'exemple ci-dessus pour modifier les composants de classe. Un décorateur est une méthode qui passe un composant de classe en paramètre.

Les décorateurs vous permettent d'écrire des composants plus flexibles et plus lisibles. Si vous ne souhaitez pas utiliser de décorateur, vous pouvez faire ceci :

class ProfileContainer extends Component {
 // Component code
}
export default observer(ProfileContainer)


Fermeture

Essayez d'éviter de passer des fermetures dans les composants enfants, tels que :

<input
 type="text"
 value={model.name}
 // onChange={(e) => { model.name = e.target.value }}
 // ^ Not this. Use the below:
 onChange={this.handleChange}
 placeholder="Your Name"/>

Remarque : Si input est un composant React, cela déclenchera automatiquement son redessin, que d'autres accessoires aient ou non changé.

La vérification de cohérence est la partie la plus gourmande en ressources de React. N'ajoutez pas de travail supplémentaire ici. La meilleure façon de gérer le problème dans l’exemple ci-dessus est de transmettre une méthode de classe, qui sera plus lisible et plus facile à déboguer. Tel que :

import React, { Component } from 'react'
import { observer } from 'mobx-react'
import { string, object } from 'prop-types'
// Separate local imports from dependencies
import ExpandableForm from './ExpandableForm'
import './styles/ProfileContainer.css'
// Use decorators if needed
@observer
export default class ProfileContainer extends Component {
 state = { expanded: false }
 // Initialize state here (ES7) or in a constructor method (ES6)
 
 // Declare propTypes as static properties as early as possible
 static propTypes = {
  model: object.isRequired,
  title: string
 }
 // Default props below propTypes
 static defaultProps = {
  model: {
   id: 0
  },
  title: 'Your Name'
 }
 // Use fat arrow functions for methods to preserve context (this will thus be the component instance)
 handleSubmit = (e) => {
  e.preventDefault()
  this.props.model.save()
 }
 
 handleNameChange = (e) => {
  this.props.model.name = e.target.value
 }
 
 handleExpand = (e) => {
  e.preventDefault()
  this.setState(prevState => ({ expanded: !prevState.expanded }))
 }
 
 render() {
  // Destructure props for readability
  const {
   model,
   title
  } = this.props
  return ( 
   
    // Newline props if there are more than two
    

     

{title}

      { model.name = e.target.value }}       // Avoid creating new closures in the render method- use methods like below       onChange={this.handleNameChange}       placeholder="Your Name"/>     

   
  )  } }

方法组件

这类组件没有state没有props,也没有方法。它们是纯组件,包含了最少的引起变化的内容。经常使用它们。

propTypes

import React from 'react'
import { observer } from 'mobx-react'
import { func, bool } from 'prop-types'
import './styles/Form.css'
ExpandableForm.propTypes = {
 onSubmit: func.isRequired,
 expanded: bool
}
// Component declaration

我们在组件的声明之前就定义了propTypes

分解Props和defaultProps

import React from 'react'
import { observer } from 'mobx-react'
import { func, bool } from 'prop-types'
import './styles/Form.css'
ExpandableForm.propTypes = {
 onSubmit: func.isRequired,
 expanded: bool,
 onExpand: func.isRequired
}
function ExpandableForm(props) {
 const formStyle = props.expanded ? {height: 'auto'} : {height: 0}
 return (
  <form style={formStyle} onSubmit={props.onSubmit}>
   {props.children}
   <button onClick={props.onExpand}>Expand</button>
  </form>
 )
}

我们的组件是一个方法。它的参数就是props。我们可以这样扩展这个组件:

import React from 'react'
import { observer } from 'mobx-react'
import { func, bool } from 'prop-types'
import './styles/Form.css'
ExpandableForm.propTypes = {
 onSubmit: func.isRequired,
 expanded: bool,
 onExpand: func.isRequired
}
function ExpandableForm({ onExpand, expanded = false, children, onSubmit }) {
 const formStyle = expanded ? {height: 'auto'} : {height: 0}
 return (
  <form style={formStyle} onSubmit={onSubmit}>
   {children}
   <button onClick={onExpand}>Expand</button>
  </form>
 )
}

现在我们也可以使用默认参数来扮演默认props的角色,这样有很好的可读性。如果expanded没有定义,那么我们就把它设置为false

但是,尽量避免使用如下的例子:

const ExpandableForm = ({ onExpand, expanded, children }) => {

看起来很现代,但是这个方法是未命名的。

如果你的Babel配置正确,未命名的方法并不会是什么大问题。但是,如果Babel有问题的话,那么这个组件里的任何错误都显示为发生在 <>里的,这调试起来就非常麻烦了。

匿名方法也会引起Jest其他的问题。由于会引起各种难以理解的问题,而且也没有什么实际的好处。我们推荐使用function,少使用const

装饰方法组件

由于方法组件没法使用装饰器,只能把它作为参数传入别的方法里。

import React from 'react'
import { observer } from 'mobx-react'
import { func, bool } from 'prop-types'
import './styles/Form.css'
ExpandableForm.propTypes = {
 onSubmit: func.isRequired,
 expanded: bool,
 onExpand: func.isRequired
}
function ExpandableForm({ onExpand, expanded = false, children, onSubmit }) {
 const formStyle = expanded ? {height: 'auto'} : {height: 0}
 return (
  <form style={formStyle} onSubmit={onSubmit}>
   {children}
   <button onClick={onExpand}>Expand</button>
  </form>
 )
}
export default observer(ExpandableForm)

只能这样处理:export default observer(ExpandableForm)

这就是组件的全部代码:

import React from 'react'
import { observer } from 'mobx-react'
import { func, bool } from 'prop-types'
// Separate local imports from dependencies
import './styles/Form.css'
// Declare propTypes here, before the component (taking advantage of JS function hoisting)
// You want these to be as visible as possible
ExpandableForm.propTypes = {
 onSubmit: func.isRequired,
 expanded: bool,
 onExpand: func.isRequired
}
// Destructure props like so, and use default arguments as a way of setting defaultProps
function ExpandableForm({ onExpand, expanded = false, children, onSubmit }) {
 const formStyle = expanded ? { height: 'auto' } : { height: 0 }
 return (
  <form style={formStyle} onSubmit={onSubmit}>
   {children}
   <button onClick={onExpand}>Expand</button>
  </form>
 )
}
// Wrap the component instead of decorating it
export default observer(ExpandableForm)

条件判断

某些情况下,你会做很多的条件判断:

<p id="lb-footer">
 {props.downloadMode && currentImage && !currentImage.video && currentImage.blogText
 ? !currentImage.submitted && !currentImage.posted
 ? <p>Please contact us for content usage</p>
  : currentImage && currentImage.selected
   ? <button onClick={props.onSelectImage} className="btn btn-selected">Deselect</button>
   : currentImage && currentImage.submitted
    ? <button className="btn btn-submitted" disabled>Submitted</button>
    : currentImage && currentImage.posted
     ? <button className="btn btn-posted" disabled>Posted</button>
     : <button onClick={props.onSelectImage} className="btn btn-unselected">Select post</button>
 }
</p>

这么多层的条件判断可不是什么好现象。

有第三方库JSX-Control Statements可以解决这个问题。但是与其增加一个依赖,还不如这样来解决:

<p id="lb-footer">
 {
  (() => {
   if(downloadMode && !videoSrc) {
    if(isApproved && isPosted) {
     return <p>Right click image and select "Save Image As.." to download</p>
    } else {
     return <p>Please contact us for content usage</p>
    }
   }
   // ...
  })()
 }
</p>

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

JsChart的组件使用详解

JS的图片处理与合成详解

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!

Déclaration:
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