React 組件
文章目錄
React書寫的一切用戶界面都是基於組件的,將界面分割成一些獨立的,可複用的部件.
一.聲明組件
1.ES5寫法:React.createClass()
最老版本的用法,不建議使用,已經廢棄了
實際上,createClass() 本質是一個工廠函數
雖然這種方法已經廢棄了,但是Facebook出了一個能代替React.createClass() 的替代品,需要使用create-react-class
模塊,先安裝
$ npm install create-react-class -S
import React from 'react';
var createReactClass = require('create-react-class');
var Greeting = createReactClass({
render: function () {
return <h1>使用create-react-class模塊創建react組件</h1>;
}
});
export default Greeting;
2.ES6寫法:React.Component
目前官方極爲推薦的創建有狀態組件的方式
支持
class語法 (狀態 屬性 生命週期)
[email protected] =>class生命週期寫法升級
import React from 'react';
import ReactDOM from 'react-dom';
class Animal extends React.Component {
render() {
return (
<div>Animal組件</div>
)
}
}
ReactDOM.render(
<div>
<Animal></Animal>
</div>,
document.getElementById('root')
);
類定義的組件
- 定義一個類,類名就是組件名
- 這個類需要繼承
React.Component
基礎組件 - 類中的render函數是必須的,render函數中的return出來的是一段JSX語法,這一段JSX語法就是這個組件的模版的內容
3.函數式組件
無狀態函數式寫法
不支持狀態 屬性 生命週期
[email protected]
=> 支持狀態 屬性 “生命週期” React Hooks
import React from 'react';
import ReactDOM from 'react-dom';
const Cat = () => {
return (
<div>
Cat組件
</div>
);
}
ReactDOM.render(
<div>
<Cat></Cat>
</div>,
document.getElementById('root')
);
函數式的定義組件
- 定義一個函數,然後return出來一段JSX語法,這一段JSX語法就是這個組件的模版的內容
- 函數名稱就是組件的名字,[所以首字母需要大寫()
PS:組件模版內容,如果需要換行的話,return後面需要寫小括號
()括起來,因爲原生js,是會返回undefind
2.模版內容只能有一個跟元素
二.組件注意事項
1.組件名首字母大寫
組件名,在被引用時 首字母必須大寫 編譯時會被認爲是自定義組件,如果寫成了小寫,會被認爲是原生js的dom節點
2.一個根元素
組件的最外層必須有一個標籤包裹,不能有兄弟元素
3.return需要加上小括號
return加上小括號,可以回車,如果內容多了,肯定不會寫成一行,原生中return後面沒有跟內容,會返回undefind
4.組件是可以嵌套的
組件是可以嵌套的,如父子組件
三.狀態(state)
每個React組件都有自己的狀態(除了函數式組件外),state只存在於組件自身內部,用來存儲自身的數據,相當於Vue中的data選項
1.定義state
在組件內部的構造器中,直接定義
this.state
constructor(props) {
super(props);
this.state = {
data: {
name: 'liuqiao',
age: 18
}
};
}
在ES7中可以直接省略構造器,直接在當前Class
中定義也可以,但是爲了規範,建議還是不要省略
// 注意,這裏是es7的寫法
//不是狀態,單純只是變量
a=10;
//狀態
state = {
name: 'liuqiao',
age: 18
}
2.訪問state
同樣,在需要使用當前狀態的地方,通過
this.state
訪問狀態
render() {
return (
<div>
我的名字叫{this.state.data.name}
</div>
);
}
3.改變state
改變state時,使用React內置的
setState()
方法修改state,每當使用setState時,React會將需要更新的state合併後放入狀態隊列,觸發調和過程,而不是立即更新state.所以,setState是異步的
this.setState({
username:'xiaohong'
});
在需要修改的地方觸發此方法即可!另外,如果要修改setState
裏面的對象的某一屬性,但不會修改其他的屬性呢?
this.state = {
username:'xiaoming',
data: {
name: 'liuqiao',
age: 18,
address:'深圳',
like:['爬山','跑步']
}
};
比如我要當前狀態中的data對象中的name屬性,但是其他屬性不修改,我不可能,爲了修改一個name屬性,把其他的都在setState裏都帶上吧,那樣肯定是不行的,所以我提供瞭如下方法:
1.方法一
let newData = { ...this.state.data };
newData.name=30;
this.setState({
data: newData
});
採用展開運算符,全部展開,然後只賦值需要修改的屬性即可.其實原理呢,就是將原來的對象淺拷貝一個新對象,然後新對象改變屬性之後,再淺拷貝回來
2.方法二
let newData = Object.assign(this.state.data, {
['age']: 30
});
this.setState({
data: newData
});
採用Object.assign方法功能,其原理就是此方法的特性可以合併具有相同屬性的對象
3.方法三
let data=this.state.data;
data.age=30;
this.setState({
data
});
4.多個改變satae操作情況
culeCount = () => {
this.setState({
count: this.state.count + 1
});
this.setState({
count: this.state.count + 1
});
this.setState({
count: this.state.count + 10
});
// 這裏多個setState操作,會被合併,只會執行最後一次的setState,進行了批量更新優化
}
如果遇到某個函數內進行了多個setSatae的情況,會被合併,整合上面的setState,如果有重複的,只會執行最後一次的setState,進行了批量更新優化
5.setState異步
setState()方法接收2個參數,後面參數可以選
this.setState({
myname: 'xiaoming'
}, () => {
//2.再打印
console.log("我是異步的" + this.state.myname);
//
});
//1.先打印
console.log(this.state.myname);
原理:狀態更新是異步的,這裏的回調函數,會等待狀態更新完,並且dom更新完之後,纔會被調用,原因是創建虛擬dom,diff算法對比舊的dom節點,和文檔碎片,進行最小化重新渲染
6.setState同步
setState在ajax,原生事件,setTimeout是同步的
handleClick2 = () => {
setTimeout(() => {
this.setState({
myname: 'xiaohong'
});
console.log(this.state.myname);
this.setState({
myname: 'xiaofang'
});
console.log(this.state.myname);
}, 0);
}
官網的一句話:setState 並不保證是同步的!所以,得出結論:setState是否同步異步,是得看情況的,當setState在ajax,原生事件,setTimeout是同步的,其他情況是異步的
四.事件綁定
1.匿名箭頭函數寫法
比較簡潔,適合處理代碼少,簡潔的邏輯
<button onClick={() => {
console.log(this.refs.username.value)
}}>提交(匿名箭頭函數寫法)</button>
2.自定義函數寫法
會存在this指向問題,需要使用bind強制改變this指向 注意,必須使用bind纔可以,call和 apply不行
原因是call和apply改變this指向後,會立即執行函數
<button onClick={this.submitLogin.bind(this)}>提交(自定義函數寫法)</button>
submitLogin(e) {
//e是事件源
console.log('自定義函數寫法',e);
}
3.自定義聲明式箭頭函數寫法
一般推薦這種方式
<button onClick={this.submitOK}>提交(自定義聲明式箭頭函數寫法)</button>
submitOK=()=>{
console.log('外部自定義函數', this.refs.username.value);
}
4.改編第一種寫法,推崇這種
原理是使用箭頭函數做中轉,就不會有this指向問題了
<button onClick={(e)=>this.submitLogin('liuqiao','123')}>改編第一種 箭頭函數做中轉</button>
submitLogin(username,pwd,e) {
//e是事件源
console.log('外部自定義函數', username,pwd,e);
}