Maison  >  Article  >  développement back-end  >  Analyse pratique de l'écriture de projets de composants React

Analyse pratique de l'écriture de projets de composants React

php中世界最好的语言
php中世界最好的语言original
2018-03-06 13:24:331166parcourir

Parce que l'idée de conception de React est extrêmement unique, il s'agit d'une innovation révolutionnaire, offre des performances exceptionnelles et la logique du code est très simple. Par conséquent, de plus en plus de gens y prêtent attention et l’utilisent. Cet article partage avec vous l'ensemble du processus d'écriture des pratiques du projet de composants React à travers des exemples. Les amis qui sont intéressés peuvent s'y référer.

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 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 un composant de classe, lorsque vous passez une méthode à un composant enfant, il faut pour vous assurer qu'ils sont appelés avec le bon this. Cela se fait généralement lors de sa transmission à 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 sais pas quelle est 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 oeil à 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.

Décorateur

@observer
export default class ProfileContainer extends Component {

Si vous connaissez certaines bibliothèques, telles que mobx, vous pouvez l'utiliser Exemple pour modifier les composants de la 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. Par exemple :


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"/>

) } }

Composant de méthode

Ce type de composant n'a pas d'état, pas d'accessoires et pas de méthodes. Ce sont des composants purs et contiennent le moins de contenu provoquant des modifications. Utilisez-les souvent.

propTypes

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

Nous définissons propTypes avant la déclaration du composant.

Décomposer les Props et defaultProps


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

Notre composant est une méthode. Son paramètre est props. Nous pouvons étendre ce composant comme ceci :


import React from &#39;react&#39;
import { observer } from &#39;mobx-react&#39;
import { func, bool } from &#39;prop-types&#39;
import &#39;./styles/Form.css&#39;
ExpandableForm.propTypes = {
 onSubmit: func.isRequired,
 expanded: bool,
 onExpand: func.isRequired
}
function ExpandableForm({ onExpand, expanded = false, children, onSubmit }) {
 const formStyle = expanded ? {height: &#39;auto&#39;} : {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有问题的话,那么这个组件里的任何错误都显示为发生在 a8093152e673feb7aba1828c43532094里的,这调试起来就非常麻烦了。

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

装饰方法组件

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


import React from &#39;react&#39;
import { observer } from &#39;mobx-react&#39;
import { func, bool } from &#39;prop-types&#39;
import &#39;./styles/Form.css&#39;
ExpandableForm.propTypes = {
 onSubmit: func.isRequired,
 expanded: bool,
 onExpand: func.isRequired
}
function ExpandableForm({ onExpand, expanded = false, children, onSubmit }) {
 const formStyle = expanded ? {height: &#39;auto&#39;} : {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 &#39;react&#39;
import { observer } from &#39;mobx-react&#39;
import { func, bool } from &#39;prop-types&#39;
// Separate local imports from dependencies
import &#39;./styles/Form.css&#39;
// 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: &#39;auto&#39; } : { 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>

使用大括号包起来的IIFE,然后把你的if表达式都放进去。返回你要返回的组件。

相关推荐:

React组件的性能优化方法

关于React组件项目实践

React Native如何实现图片查看组件


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