Heim  >  Artikel  >  Backend-Entwicklung  >  Praktische Analyse des Schreibens von React-Komponentenprojekten

Praktische Analyse des Schreibens von React-Komponentenprojekten

php中世界最好的语言
php中世界最好的语言Original
2018-03-06 13:24:331165Durchsuche

Da die Designidee von React äußerst einzigartig ist, handelt es sich um eine revolutionäre Innovation, weist eine hervorragende Leistung auf und die Codelogik ist sehr einfach. Daher achten immer mehr Menschen darauf und nutzen es. In diesem Artikel erfahren Sie anhand von Beispielen den gesamten Prozess des Schreibens von React-Komponentenprojekten.

Als ich anfing, React zu schreiben, sah ich viele Möglichkeiten, Komponenten zu schreiben. Es gibt hundert Möglichkeiten, hundert Tutorials zu schreiben. Obwohl React selbst ausgereift ist, scheint es keinen „richtigen“ Weg zu geben, es zu verwenden. Deshalb fasse ich hier die Erfahrungen mit der Verwendung von React zusammen, die unser Team im Laufe der Jahre gesammelt hat. Ich hoffe, dieser Artikel ist für Sie nützlich, egal ob Sie Anfänger oder Veteran sind.

Bevor Sie beginnen:

Wir verwenden die ES6- und ES7-Syntax. Wenn Sie sich über den Unterschied zwischen Anzeigekomponenten und Containerkomponenten nicht ganz im Klaren sind, empfehlen wir Ihnen, zunächst diesen Artikel zu lesen. Wenn Sie Vorschläge oder Fragen haben, hinterließ Duqing eine Nachricht in den Kommentaren zu klassenbasierten Komponenten

Heutzutage werden React-Komponenten im Allgemeinen mithilfe klassenbasierter Komponenten entwickelt. Als nächstes schreiben wir unsere Komponente in die gleiche Zeile:

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

Ich mag CSS in Javascript. Allerdings ist diese Methode des Schreibstils noch zu neu. Deshalb führen wir in jeder Komponente CSS-Dateien ein. Darüber hinaus werden lokal eingeführte Importe und globale Importe durch eine Leerzeile getrennt.

Initialisierungsstatus


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 }

Sie können die alte Methode verwenden, um constructor in state zu initialisieren. Weitere relevante Informationen finden Sie hier. Aber wir wählen einen klareren Ansatz.

Außerdem haben wir darauf geachtet, vor der Klasse export default hinzuzufügen. (Anmerkung des Übersetzers: Obwohl dies bei Verwendung von Redux möglicherweise nicht korrekt ist.)

propTypes und 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 und defaultProps sind statische Eigenschaften. Definieren Sie es so früh wie möglich in der Komponentenklasse, damit andere Entwickler es beim Lesen des Codes sofort bemerken können. Sie können als Dokumentation dienen.

Wenn Sie React 15.3.0 oder höher verwenden, müssen Sie das prop-types-Paket separat importieren, anstatt React.PropTypes zu verwenden. Weitere Inhalte werden hierher verschoben.

Alle Ihre Komponenten sollten Requisitentypen haben.

Methoden


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 })
 }
 // ...
}


In einer Klassenkomponente, wenn Sie eine Methode an eine untergeordnete Komponente übergeben, Need um sicherzustellen, dass sie mit der richtigen Funktion aufgerufen werden. Dies geschieht normalerweise, wenn es an eine untergeordnete Komponente übergeben wird: this.handleSubmit.bind(this).

Es ist viel einfacher, die Pfeilmethode von ES6 zu verwenden. Es behält automatisch den richtigen Kontext bei (this).

Übergeben Sie eine Methode an setState

Im obigen Beispiel gibt es diese Zeile:

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

setStateEs ist tatsächlich asynchron! Um die Leistung zu verbessern, ruft React mehrere setState zusammen auf. Daher ändert sich der Status möglicherweise nicht unbedingt sofort nach dem Aufruf von setState.

Wenn Sie also setState aufrufen, können Sie sich nicht auf den aktuellen Statuswert verlassen. Weil ich seinen Wert überhaupt nicht kenne.

Lösung: Übergeben Sie eine Methode an setState und übergeben Sie den Statuswert, bevor Sie diese Methode als Parameter aufrufen. Schauen Sie sich das Beispiel an:

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

Danke an Austin Wood für die Hilfe.

Komponenten zerlegen

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}

) } }

Bei mehrzeiligen props sollte jede Requisite eine separate Zeile belegen. Genau wie das obige Beispiel. Der beste Weg, dieses Ziel zu erreichen, ist die Verwendung einer Reihe von Tools: Prettier.

Decorator

@observer
export default class ProfileContainer extends Component {

Wenn Sie einige Bibliotheken kennen, z. B. mobx, können Sie sie verwenden Beispiel zum Ändern von Klassenkomponenten . Ein Dekorator ist eine Methode, die eine Klassenkomponente als Parameter übergibt.

Dekoratoren ermöglichen das Schreiben flexiblerer und lesbarerer Komponenten. Wenn Sie keinen Dekorator verwenden möchten, können Sie Folgendes tun:

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


Schließung

Versuchen Sie, die Übergabe von Schließungen in untergeordneten Komponenten zu vermeiden. wie zum Beispiel:

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

Hinweis: Wenn input eine React-Komponente ist, wird dadurch automatisch das Neuzeichnen ausgelöst, unabhängig davon, ob sich andere Requisiten geändert haben.

Konsistenzprüfung ist der ressourcenintensivste Teil von React. Fügen Sie hier keine zusätzliche Arbeit hinzu. Der beste Weg, das Problem im obigen Beispiel zu lösen, besteht darin, eine Klassenmethode zu übergeben, die besser lesbar und einfacher zu debuggen ist. Zum Beispiel:


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

) } }

Methodenkomponente

Dieser Komponententyp hat keinen Zustand, keine Requisiten und keine Methoden. Sie sind reine Komponenten und enthalten die geringste Menge an Inhalten, die Veränderungen verursachen. Benutze sie oft.

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

Wir definieren propTypes vor der Deklaration der Komponente.

Props und Standardpropps zerlegen


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>
 )
}

Unsere Komponente ist eine Methode. Sein Parameter ist props. Wir können diese Komponente wie folgt erweitern:


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如何实现图片查看组件


Das obige ist der detaillierte Inhalt vonPraktische Analyse des Schreibens von React-Komponentenprojekten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn