React基本語法

麵條請不要欺負漢堡發表於2018-05-28

一.JSX

1.什麼是JSX

 JSX 是 JavaScrip 的一種擴充套件語法。JSX是React的核心組成部分,它使用XML標記的方式去直接宣告介面,介面元件之間可以互相巢狀。可以理解為在JS中編寫與XML類似的語言,一種定義帶屬性樹結構(DOM結構)的語法,它的目的不是要在瀏覽器或者引擎中實現,它的目的是通過各種編譯器將這些標記編譯成標準的JS語言。

下面就是jsx的語法

function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}

const user = {
  firstName: '劉',
  lastName: '小車'
};

const element = (
  <h1>
    Hello, {formatName(user)}!
  </h1>
);

ReactDOM.render(
  element,
  document.getElementById('root')
);

//輸出 Hello 劉小車!
2.JSX的特點:
A.類XML語法容易接受,結構清晰
B.增強JS語義
C.抽象程度高,遮蔽DOM操作,跨平臺

D.程式碼模組化

3.基本語法

JSX本身就和XML語法類似,可以定義屬性以及子元素。唯一特殊的是可以用大括號來加入JavaScript表示式。遇到 HTML 標籤(以 < 開頭),就用 HTML 規則解析;遇到程式碼塊(以 { 開頭),就用 JavaScript 規則解析。不加引用 (加引號就會被當成字串)

var arr = [
 <h1>Hello world!</h1>,
 <h2>React is awesome</h2>,
];
ReactDOM.render(
 <div>{arr}</div>,
 document.getElementById('example')
);
這個就是一個簡單的html與js混用的例子。arr變數中存在html元素,div中又使用了arr這個js變數。轉化成純javascript的話:

(1).指定屬性值

A.使用雙引號來指定字串字面量作為屬性值

const element = <div tabIndex="0"></div>;

B.花括號嵌入一個 JavaScript 表示式作為屬性值

const element = <img src={user.avatarUrl}></img>;

(2).註釋

在 JSX 裡使用註釋也很簡單,就是沿用 JavaScript,唯一要注意的是在一個元件的子元素位置使用註釋要用 {} 包起來。

(3).支援的標籤和屬性

在React中,所有DOM屬性和屬性(包括事件處理程式)都應該是camelCased的。例如,HTML屬性tabindex對應tabIndex於React中的屬性。唯一的例外是aria-*和data-*屬性,應小寫。例如,你可以繼續aria-label作為aria-label

1.class命名: React DOM 使用駝峰(camelCase)屬性命名約定, 而不是HTML屬性名稱。

例如,class 在JSX中變為className,tabindex 變為 tabIndex

<div tabIndex="-1" />     
<div className="Button" />
<input readOnly={true} />  

2.樣式設定

React會自動將“px”字尾附加到某些數字內聯樣式屬性。如果您想使用“px”以外的單位,請將該值指定為具有所需單位的字串。例如:

// Result style: '10px'
<div style={{ height: 10 }}>
  Hello World!
</div>

// Result style: '10%'
<div style={{ height: '10%' }}>
  Hello World!
</div>

參考官網

二.元件

(1).元件繼承+組合

A.組合

import React from 'react';
class App extends React.Component {
	render() {
		const user = '丫丫';
		const ProfilePic1 = (props) => {
			  return (
			   		<div>組合1:{props.username}</div>
			  );
		};
		const ProfilePic2 = (props) => {
			  return (
			   		<div>組合2:{props.username}</div>
			  );
		};
		return (
			<div>
				<h1>Hello, {user}!</h1>
				<ProfilePic1 username="元件小妹1"/>
				<ProfilePic2 username="元件小妹2"/>
			</div>
		);
	}
}

B.繼承

注意:return 要加div來包裹元件

import React from 'react';
class App extends React.Component {
	render() {
		function formatName(user) {
  			return user.firstName + user.lastName;
		}
		const user = {
		  	firstName: '劉',
		  	lastName: '小車'
		};
		return (
			<div>
				<h1>Hello, {formatName(user)}!</h1>
				<Childdiv></Childdiv>
			</div>
		);
	}
}
class Childdiv extends React.Component {
	render() {
		const name='麗麗'
		return (
			<div>我是{name}</div>
		);
	}
}
export default App;

注意:

元件標籤裡面包含的子元素會通過 props.children 傳遞進來 :this.props.children

import React from 'react';
class App extends React.Component {
	render() {
		const user = '丫丫';
		const Parent = (props) =>{
			  return (
			   		 <div>元件標籤裡面包含的子元素:{props.username}{props.children}</div>
			  );
		};
		return (
			<div>
				<h1>Hello, {user}!</h1>
				<Parent username="hello"><span>props.children</span></Parent>
			</div>
		);
	}
}

(2).props 元件之間傳遞資料

使用:<元件 資料="值"></元件>的形式傳遞

元件之間:使用this.props獲取值
如果元件只有render函式,還可以用函式形式寫元件

import React from 'react';
class App extends React.Component {
	render() {
		const user = '丫丫'
		return (
			<div>
				<h1>Hello, {user}!</h1>
				<Childdiv name="麗麗"></Childdiv>
				<Welcome name="徐曉高"></Welcome>
			</div>
		);
	}
}
function Welcome(props) {
  	return <h1>用函式形式寫元件,{props.name}</h1>;
}
//元件之間的傳值:{this.props.name}
class Childdiv extends React.Component {
	render() {
		return (
			<div>我是{this.props.name}</div>
		);
	}
}

export default App;


補充:

無論你用函式或類的方法來宣告元件, 它都無法修改其自身 props. 思考下列 sum (求和)函式:

function sum(a, b) {
  return a + b;
}
這種函式稱為 “純函式” ,因為它們不會試圖改變它們的輸入,並且對於同樣的輸入,始終可以得到相同的結果。

以下是非純函式, 因為它改變了自身的輸入值:

function withdraw(account, amount) {
  account.total -= amount;
}

注意:

所有 React 元件都必須是純函式,並禁止修改其自身 props

當然, 應用 UI 總是動態的,並且隨時有可以改變。 state 允許 React 元件在不違反上述規則的情況下, 根據使用者操作, 網路響應, 或者其他隨便什麼東西, 來動態地改變其輸出。

(3).元件內部state(專案管理狀態) 

A.特點:

a.JSX本質就是js,所以直接陣列.map渲染列表

b.constructor設定出事狀態,記得執行super(props)

c.如state就是一個不可變的物件,使用this.state獲取

import React from 'react';
class App extends React.Component {
	render() {
		const user = '丫丫';
		return (
			<div>
				<h1>Hello, {user}!</h1>
				<Childdiv name="麗麗"></Childdiv>
			</div>
		);
	}
}
//元件之間的傳值:{this.props.name}
class Childdiv extends React.Component {
	//新增一個 類建構函式(class constructor) 初始化 this.state
	constructor(props){
		super(props);
		this.state={
			solders:['蘋果','梨','香蕉']
		}

	}
	render() {
		return (
			<div>
				<div>我是{this.props.name},我有以下這些水果:</div>
				<ul>
					{this.state.solders.map(v=>{
						return <li key={v}>{v}</li>
					})}
				</ul>
			</div>
		);
	}
}

export default App;

注意:渲染列表ul的時候,li要有key

(4).生命週期

React元件有若干鉤子函式,在元件不同的狀態執行
a.初始化週期
b.元件重新渲染生命週期
c.元件解除安裝宣告週期


//元件之間的傳值:{this.props.name}
class Childdiv extends React.Component {
	//建構函式
	constructor(props){
		super(props);
		this.state={
			solders:['蘋果','梨','香蕉']
		}
	}
	//生命週期函式 render 之前呼叫 :在這個方法裡面呼叫 setState 改變狀態
  	componentWillMount() {
  		console.log('元件馬上就要載入了。。')
  	}
  	//生命週期函式 render之後呼叫:這裡可以獲取元件的DOM節點
  	componentDidMount() {
		console.log('元件載入完畢!')
	}
	render() {
		console.log('元件正在載入了。。')
		return (
			<div>
				<div>我是{this.props.name},我有以下這些水果:</div>
				<ul>
					{this.state.solders.map(v=>{
						return <li key={v}>{v}</li>
					})}
				</ul>
			</div>
		);
	}
}

(5).處理事件

1.例項

通過 React 元素處理事件跟在 DOM 元素上處理事件非常相似。但是有一些語法上的區別:
a.React 事件使用駝峰命名,而不是全部小寫。
b.通過 JSX , 你傳遞一個函式作為事件處理程式,而不是一個字串。

如onClick點選事件:
   a.JSX裡,onClick={this.函式名}來繫結事件
   b.this引用的問題,需要在建構函式裡用bind繫結this

   c.this.setState修改state,記得返回新的state,而不是修改

import React from 'react';
class App extends React.Component {
	render() {
		const user = '丫丫';
		return (
			<div>
				<h1>Hello, {user}!</h1>
				<Childdiv name="麗麗"></Childdiv>
			</div>
		);
	}
}
//元件之間的傳值:{this.props.name}
class Childdiv extends React.Component {
	//建構函式
	constructor(props){
		super(props);
		this.state={
			solders:['蘋果','梨','香蕉']
		}
		this.addfruits = this.addfruits.bind(this)
	}
	addfruits(){
		this.setState({
			solders:[...this.state.solders,'鳳梨'+ Math.random()]
		})
	}
	render() {
		return (
			<div>
				<div>我是{this.props.name},我有以下這些水果:</div>
				<button onClick={this.addfruits}>新增水果</button>
				<ul>
					{this.state.solders.map(v=>{
						return <li key={v}>{v}</li>
					})}
				</ul>
			</div>
		);
	}
}

export default App;

注意要顯式呼叫 bind(this) 將事件函式上下文繫結要元件例項上,這也是 React 推崇的原則:沒有黑科技,儘量使用顯式的容易理解的 JavaScript 程式碼。

注意:this的問題 除了this.addfruits = this.addfruits.bind(this)或<button onClick={this.addfruits.bind(this)}>新增水果</button>的解決方式,還有如下

這裡使用箭頭函式:<button onClick={()=>this.addfruits()}>新增水果</button>

2.引數傳遞

給事件處理函式傳遞額外引數的方式:bind(this, arg1, arg2, ...)

addfruits(param, event){
		this.setState({
			solders:[...this.state.solders,param+ Math.random()]
		})
	}
	render() {
		return (
			<div>
				<div>我是{this.props.name},我有以下這些水果:</div>
				<button onClick={this.addfruits.bind(this,'鳳梨')}>新增水果</button>
				<ul>
					{this.state.solders.map(v=>{
						return <li key={v}>{v}</li>
					})}
				</ul>
			</div>
		);
	}
效果同上

React 支援的事件列表

(6).DOM的操作

React 操作DOM元素的兩種方式

1. 使用選擇器
var Btn = document.getElementById('btn')
ReactDom.findDOMNode(Btn).style.color = 'red'
2. 使用ref
在標籤內使用ref='btn'
this.refs.btn.style.color = 'red'
Refs 是訪問到元件內部DOM節點唯一可靠的方法 
注意:a.不要在 render 或者 render 之前訪問 refs,可以在 componentDidMount函式中使用
b.不要濫用 refs,比如只是用它來按照傳統的方式操作介面 UI:找到 DOM -> 更新 DOM

(7).mixin

Mixin 就是用來定義一些方法,使用這個 mixin 的元件能夠自由的使用這些方法(就像在元件中定義的一樣),所以 mixin 相當於元件的一個擴充套件,在 mixin 中也能定義“生命週期”方法。

React 的 mixins 的強大之處在於,如果一個元件使用了多個 mixins,其中幾個 mixins 定義了相同的“生命週期方法”,這些方法會在元件相應的方法執行完之後按 mixins 指定的陣列順序執行。

三.Data Flow

Data Flow 只是一種應用架構的方式,比如資料如何存放,如何更改資料,如何通知資料更改等等,所以它不是 React 提供的額外的什麼新功能,可以看成是使用 React 構建大型應用的一種最佳實踐。

這裡主要關注兩種實現:

官方的 Flux 和 更優雅的 Redux