React 組件淺析

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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章