1. 程式人生 > >react整理(一) react元件

react整理(一) react元件

說起react是一個很寬泛的東西,作為一個從零開始學習react的小白,到現在懂一點react,決心將自己學的東西一一整理,從簡單的開始著手,一是為了鞏固知識,二也是為正在學習的同學提供一些思路,三也是希望大佬能夠指出我的不妥之處,或加以補充,以更深層次的掌握react。

那麼,在學習react之前,我們應該掌握哪些知識?
1.需要熟悉javascript
2.需要使用es6,箭頭函式, 類, 模板字串, let, 和 const 宣告

react是什麼?概括為兩點:
1.用來構建UI的JS庫。
2.React 不是一個MVC框架,僅僅是檢視層(V)層的庫。

react包括哪些概念?
1.元件
2.JSX
3.Virtual DOM
4.Data Flow

第一部分

那麼接下來我們就從構建一個簡單的元件開始。

在之前,我們的js,css,html都是分離的,這種方式滿足不了我們要去實現程式碼複用。元件化,很多前框的框架都開始注重了這一點。一個元件就是一個功能模組,react框架相對來說,實現的更加徹底一些。react各個元件維護自己的狀態和UI,當狀態更變時,自動重新渲染整個元件。

構建react元件,可以是一個類,可以是一個函式。類與函式有什麼區別?
1.類是有狀態的元件,而函式是無狀態的元件。
2.通過類構建一個元件,允許有內部狀態存在,有完整的生命週期。可以使一個元件有生命力並且便於管理。
3.通過類構建必須要繼承react內建的元件類,生命週期都是繼承自react內建的元件類。
4.從效能來說,類構建要稍微慢一些。

如果是不使用生命週期是不是就可以不繼承內建的元件類呢?
答案是不能,如果是使用了class來構建react的元件,必須要繼承react的內建元件,因為class類中必須有一個render()方法來返回元件的例項。不寫render方法它就不可能返回UI,那也就不是一個元件。render方法就是生命週期之一。

首先,我們來建立一個基於class的react元件。
類構建react元件有兩種方式:
1.ES5: React.createClass
2.ES6:React.Component

React.createClass是React剛開始推薦的方式,是與ES5中原生JS來建立react元件方式。React.createClass建立一個類,接受一個物件為引數,並且需要有一個render方法來返回元件例項UI。這種方式我沒有怎麼使用過,不過基本的使用方式如下:

import React from 'react'
import ReactDom from 'react-dom'

const reactDom = React.createClass({
  getDefaultProp: function () {
    return { open: false }
  },
  getInitialState: function (){
    return { open: this.props.open}
  },
  handleClick: function(event){
    this.setState({
      open: !this.state.open
    })
  },
  render: function () {
    var open = this.state.open
    className = open ? 'switch-button' : 'btn-switch'
    return (
      <label className={className} onClick={this.handleClick.bind(this)}>
        <Input type="checkbox" checked={open} />
      </label>
    )
  }
})

ReactDOM.render(
  <reactDom />,
  document.getElementById('root')
)

ReactDom是React的最基本方法用於將模板轉為HTML語言,並插入指定的DOM節點。
雖然沒有使用過,但是它的弊端就是:
1.會自動繫結函式方法,造成不必要的效能開銷
2.mixins不夠直觀,自然。(這一點在es6中已經沒有使用了,它主要的作用就是,不同的元件之間,會使用到相同的功能,如果一個元件使用了多個 mixins,其中幾個 mixins 定義了相同的“生命週期方法”,這些方法會在元件相應的方法執行完之後按 mixins 指定的陣列順序執行),可參考http://wiki.jikexueyuan.com/project/react-tutorial/mixin.html

接下來要說的就是目前正使用的方法,使用es6方式來構建react元件。按照上面的方法,應該寫成以下方式。

export default class reactDom extends Component {
  constructor(props){
    super(props);
    this.state = {
      open: false
    }
  }

  getDefaultProp() {
    return { open: false }
  }

  getInitialState(){
    return { open: this.props.open}
  }

  handleClick (e){
    this.setState({
      open: !this.state.open
    })
  }

  render(){
    return (
      <label className={className} onClick={this.handleClick.bind(this)}>
        <Input type="checkbox" checked={open} />
      </label>
    )
  }
}

那麼es5與es6在寫法上有什麼更具體的區別呢?

1.寫法上的不同
React.creatClass 新建立的Class賦給一個常量,再添上render方法來構建出一個基本的元件
es5的寫法:

const Contacts = React.createClass({
	render() {
		return (
			<div></div>
		)
		}
	})
export default Contacts;

es6的寫法:

export default class Contacts extends React.Component({
	construct(props){
		super(this)
		this.state = {}
	}
	render(){
		return(
		<div></div>
		)
	}
})

es6的不同,我們使用super這個函式,來為React.component傳遞屬性,所以需要引用construct()這個方法。es6的寫法更加具有類的意義。

2.propType 和 getDefaultProps
他們的區別在於如何使用、宣告預設屬性和型別,以及如何設定類初始化狀態。propType的作用是,當父元件給子元件傳參時,定義父元件給子元件傳值的型別;getDefaultProps/DefaultProps的任務是父元件給子元件傳參沒有給定預設值時,可以在getDefaultProps/DefaultProps中定義。
es5寫法:

const Contacts = React.createClass({
    propType: {},
    getDefaultProps: (){
 	   return {
		  }
	    }
	render() {
		return (
			<div></div>
		)
	}
})
export default Contacts

在呼叫 React.createClass,定義propTypes 的物件,只要給它的屬性進行賦值就能宣告對應屬性的型別。 getDefaultProps 這個函式返回了一個物件,這個物件的所有屬性將會作為元件的初始化屬性
使用es6的寫法,個人更喜歡這樣的寫法,他更簡潔直觀了:

export default Contacts  extends React.Component {
// static 不繼承例項,直接通過類來呼叫的靜態方法
	static propType = {
	},
	static defaultProps = {
	}
	render() {
		return (
			<div></div>
		)
	}
}

3.state的不同
外部資料來源我們用props來儲存資料,而state是用來管理內部資料狀態的。使用es5,state是放在getInitialState()方法中,返回一個包含元件初始化狀態的物件。
es5寫法具體如下:

const Contact = React.CreateClass{
	getInitialState () {
		return  {
		}
	}
	render(){
		return (
		<div></div>
		)
	}
}
export default Contact;

在es6中,廢除了getInitialState()這個方法,狀態的定義在construct建構函式裡。例如這樣:

export default Contact extends React.Component {
	construct (props) {
		super(props);
		this.state = {}
	}
	render(){
		return (
			<div></div>
		)
	}
}

4.this的使用不同
es5中會自動繫結this,比如說

const Contact = React.createClass({
    handleClick () {
         console.log(this)
    },
	render(){
		return (
			<div onClick={this.handleClick}></div>
		)
	}
})
export default  Contact;

這裡的this可以自動的找到當前執行環境的上下文,不用我們操心,但是這樣我們語法結構時,可能要去改變jsx部分(支援js,css,html混合在一起的寫法)結構。
如果使用的是es6的語法,this不會自動去繫結上下文,而是需要自己繫結正確的上下文,就像下面的例子一樣。

export default class Contact extends React.Component {
	handleClick () {
	console.log(this)
	}
	render () {
		return (
			<div onClick={this.handleClick.bind(this)}></div>
		)
	}
}

5.mixins
es5中還儲存有mixins這個特性,而es6中已廢棄了這個特性,取而代之的是高階元件,不過這一塊還不瞭解,會繼續學習。

接下來,我們建立一個無狀態元件
無狀態的元件我們通常是做純UI展示。不需要去定義元件狀態不用考慮元件的生命週期,就像這樣:

class MessageView extends React.Component { 
	render({ 
		return(
		   <div className="container"> 
			<div className="from"> 
				<span className="label">From: </span>
				<span className="value">JohnDoe</span>
			 </div>
		      <div className="message"> 
				<span className="label">Message: </span>
			 	<span className="value">Have a great day!</span>
		 	</div>
		 </div>
	 ) } } 
export default MessageView;

因為是純UI展示,所以也可以不考慮生命週期,不繼承Component,於是可改寫成:

export default function MessageView({message}) { 
	return( 
	<div className="container"> 
		<div className="from">
			 <span className="label">From: </span> 
			 <span className="value">{message.from}</span>
		</div>
		<div className="message">
		 	<span className="label">Message: </span>
		 	<span className="value">{message.content}</span>
		</div> 
	</div>
) }}

那麼無狀態與有狀態元件,我們怎麼用呢?
如果要考慮生命週期,那麼就用使用類構建react例項,如果不考慮生命週期,那麼使用無狀態函式式構建。
一般來說,ES6的寫法是優於ES5寫法的。

以上是我的總結,如有疑問可留言。

參考資料:
https://www.w3cplus.com/react/stateful-vs-stateless-components.html © w3cplus.com