自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

編寫React組件的最佳實踐

開發(fā) 后端
在我第一次編寫 React 代碼的時候,我見發(fā)現(xiàn)許多不同的方法可以用來編寫組件,不同教程教授的內(nèi)容也大不相同。盡管從那時候起框架已經(jīng)相當(dāng)成熟,但并沒有一種固定的“正確”方式指導(dǎo)。

在我***次編寫 React 代碼的時候,我見發(fā)現(xiàn)許多不同的方法可以用來編寫組件,不同教程教授的內(nèi)容也大不相同。盡管從那時候起框架已經(jīng)相當(dāng)成熟,但并沒有一種固定的“正確”方式指導(dǎo)。


在 MuseFind 工作的一年里,我們的團隊編寫了許多 React 組件,后期我們對方法進行了優(yōu)化直到滿意為止。

本指南描述了我們推薦的***實踐,不管你是一名初學(xué)者還是有經(jīng)驗的老手,希望它能對你有所幫助。

在我們開始之前,有幾個地方要注意一下:

  • 我們使用的是 ES6 和 ES7 的語法。

  • 如果你對于現(xiàn)實和容器組件兩者之間的區(qū)別不甚明了,建議首先閱讀一下這個。

  • 如果有任何建議、疑問或者感想,請通過評論來讓我們知曉。

基于類的組件

基于類的組件具有豐富狀態(tài)而且可以含有方法。我們要盡可能有節(jié)制地去使用,因為它們也有特定的適用場合。

讓我們使用一行一行的代碼逐步地將我們的組件構(gòu)建起來吧。

引入 CSS

import React, {Component} from 'react'
import {observer} from 'mobx-react'

import ExpandableForm from './ExpandableForm'
import './styles/ProfileContainer.css'

我喜歡在 JavaScript 中操作 CSS,這在理論上這樣做是可行的。不過它仍然是一種新的創(chuàng)意,還沒出現(xiàn)切實可行的解決方案。不過在此之前,我們可以先為每一個組件引入一個 CSS 文件。

我們也通過另寫一行將依賴引入從本地引入獨立了出來。

狀態(tài)初始化

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 }

propTypes 和 defaultProps

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 }
 
  static propTypes = {
    model: React.PropTypes.object.isRequired,
    title: React.PropTypes.string
  }
 
  static defaultProps = {
    model: {
      id: 0
    },
    title: 'Your Name'
  }

propTypes 和 defaultProps 是靜態(tài)屬性,要在組件代碼中盡可能高的位置進行聲明。它們作為文檔放在醒目的位置,其他開發(fā)者閱讀此文件時能立即看到。

所有的組件都應(yīng)該有 propTypes。

方法

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 }
 
  static propTypes = {
    model: React.PropTypes.object.isRequired,
    title: React.PropTypes.string
  }
 
  static defaultProps = {
    model: {
      id: 0
    },
    title: 'Your Name'
  }
  handleSubmit = (e) => {
    e.preventDefault()
    this.props.model.save()
  }
  
  handleNameChange = (e) => {
    this.props.model.name = e.target.value
  }
  
  handleExpand = (e) => {
    e.preventDefault()
    this.setState({ expanded: !this.state.expanded })
  }

有了類組件,在你想子組件傳遞方法時,就得去確認它們在被調(diào)用到時所持有的 this 對象是正確的。這個一般可以通過將 this.handleSubmit.bind(this) 傳遞給子組件來達成。

我們認為這種方式更加干凈且容易,借助 ES6 的箭頭函數(shù)可以自動地維護好正確的上線文。

屬性析構(gòu)

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 }
 
  static propTypes = {
    model: React.PropTypes.object.isRequired,
    title: React.PropTypes.string
  }
 
  static defaultProps = {
    model: {
      id: 0
    },
    title: 'Your Name'
  }
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() {
    const {
      model,
      title
    } = this.props
    return ( 
      <ExpandableForm          onSubmit={this.handleSubmit}          expanded={this.state.expanded}          onExpand={this.handleExpand}>         <div>           <h1>{title}</h1>           <input             type="text"             value={model.name}             onChange={this.handleNameChange}             placeholder="Your Name"/>         </div>       </ExpandableForm>     )   } }

擁有許多屬性的組件要讓每個屬性都另起一行,如上所示。

裝飾器

@observer
export default class ProfileContainer extends Component {

如果你使用了一些像 mobx 的東西,就可以像上面這樣對類組件進行裝飾 — 這樣做跟將組件傳遞給一個函數(shù)是一樣的效果。

裝飾器是一種用來修改組件功能的靈活且可讀性好的方式。我們對其進行了廣泛的運用,包括 mobx 還有我們自己的 mobx-models 庫。

如果你不想使用裝飾器,可以這樣做:

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

閉包

要避免向子組件傳遞新的閉包,如下:

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

原因: 每次父組件渲染時,都會有一個新的函數(shù)被創(chuàng)建并傳遞給輸入。

如果輸入是一個 React 組件,不管它的其它屬性實際是否已經(jīng)發(fā)生了變化,都會自動地觸發(fā)讓它重新渲染。

調(diào)和是 React 中消耗最昂貴的部分,因此不要讓它的計算難度超過所需! 另外,傳遞一個類方法更容易閱讀、調(diào)試和修改。

如下是完整的組件代碼:

import React, {Component} from 'react'
import {observer} from 'mobx-react'
// 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: React.PropTypes.object.isRequired,
    title: React.PropTypes.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 ( 
      <ExpandableForm          onSubmit={this.handleSubmit}          expanded={this.state.expanded}          onExpand={this.handleExpand}>         // Newline props if there are more than two         <div>           <h1>{title}</h1>           <input             type="text"             value={model.name}             // onChange={(e) => { model.name = e.target.value }}             // Avoid creating new closures in the render method- use methods like below             onChange={this.handleNameChange}             placeholder="Your Name"/>         </div>       </ExpandableForm>     )   } }

函數(shù)式組件

這些組件沒有狀態(tài)和方法。它們就是單純的組件,容易理解。要盡可能常去使用它們。

propTypes

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

這里,我們將 propTypes 分配給了頂部一行的變量。在組件聲明的下面,我們對它們進行了正常的分配。

對 Props 和 defaultProps 進行析構(gòu)

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

我的組件是一個函數(shù),因此可以將它的屬性看做是參數(shù)。我們可以像下面這樣對它們進行擴展:

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

注意,我們也能以一種高度可讀的方式使用默認參數(shù)來扮演 defaultProps 的角色。如果 expanded 是 undefined, 我們就會將其設(shè)置為 false。 (這個例子有點勉強,因為是一個布爾值,不過本身對于避免對象的“Cannot read <property> of undefined“這樣的錯誤是很有用的)。

要避免如下這種 ES6 語法:

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

看著非?,F(xiàn)代,不過這里的函數(shù)實際上沒有被命令。

這樣子的名稱在 Bable 進行了正確的設(shè)置的情況下是可行的 —  但如果沒有正確設(shè)置,任何錯誤都會以在<<anonymous>>中出現(xiàn)的方式顯示,調(diào)試起來相當(dāng)麻煩。

無名的函數(shù)也會在 Jest 這個 React 測試庫中引發(fā)問題。為了避免潛在的復(fù)雜問題出現(xiàn),我們建議使用 function 而不是 const。

封裝

因為在函數(shù)式組件中不能使用裝飾器,所以你可以簡單地將它傳遞到函數(shù)中充當(dāng)參數(shù):

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

如下是完整的組件代碼:

import React from 'react'
import {observer} from 'mobx-react'
// Separate local imports from dependencies
import './styles/Form.css'

// Declare propTypes here as a variable, then assign below function declaration 
// You want these to be as visible as possible
const expandableFormRequiredProps = {
  onSubmit: React.PropTypes.func.isRequired,
  expanded: React.PropTypes.bool
}

// Destructure props like so, and use default arguments as a way of setting defaultProps
function ExpandableForm({ onExpand, expanded = false, children }{
  return (
    <form style={ expanded ? { height: 'auto' } : { height: 0 } }>       {children}       <button onClick={onExpand}>Expand</button>     </form>
  )
}

// Set propTypes down here to those declared above
ExpandableForm.propTypes = expandableFormRequiredProps

// Wrap the component instead of decorating it
export default observer(ExpandableForm)

JSX 中的條件分支

你會有不少機會去做許多條件分支渲染。如下是你想要去避免的情況:

嵌套的三元組并非不是好主意。

有一些庫可以解決這個問題 (JSX-Control Statements),不過相比引入額外的依賴,通過如下這種方式解決復(fù)雜條件分支問題要更好:

使用花括弧封裝一個 IIFE, 然后在里面放入 if 語句,可以返回任何你想要渲染的東西。注意像這樣的 IIFE 對性能會有影響,不過在大多數(shù)情況中還不足以讓我們?yōu)榇诉x擇丟掉可讀性。

還有就是當(dāng)你只想要在一個條件分支中渲染一個元素時,比起這樣做…

{
  isTrue
   ? <p>True!</p>
   : <none/>
}

… 使用短路寫法更劃算:

{
  isTrue && 
    <p>True!</p>
}
責(zé)任編輯:張燕妮 來源: 開源中國社區(qū)
相關(guān)推薦

2020-06-03 16:50:24

TypeScriptReact前端

2017-05-17 15:50:34

開發(fā)前端react

2023-07-21 01:12:30

Reactfalse?變量

2019-07-22 10:42:11

React組件前端

2020-06-01 09:40:06

開發(fā)ReactTypeScript

2022-08-19 09:01:59

ReactTS類型

2019-07-20 23:30:48

開發(fā)技能代碼

2018-01-12 14:37:34

Java代碼實踐

2011-04-15 15:16:18

代碼編程

2024-05-13 13:13:13

APISpring程序

2011-11-18 09:42:29

Ajax

2017-03-06 13:20:31

2023-11-29 09:00:55

ReactuseMemo

2023-09-13 08:00:00

JavaScript循環(huán)語句

2015-09-15 16:01:40

混合IT私有云IT架構(gòu)

2016-12-27 08:49:55

API設(shè)計策略

2011-08-18 11:05:21

jQuery

2021-04-25 11:31:45

React代碼整潔代碼的實踐

2019-09-17 09:44:45

DockerHTMLPython

2009-12-11 10:02:26

點贊
收藏

51CTO技術(shù)棧公眾號