React入門(二)

組件

1.函數式組件

  • 什么是函數式組件
    創建一個函數,只要函數中返回一個新的JSX元素,則為函數式組件
import React from 'react'
function News(props){    // 聲明函數式組件
  console.log(props);    //接收只讀屬性
  return <div>
    <ul>
      <li>webpack</li>
      <li>vue</li>
      <li>react</li>
    </ul>
  </div>
}
export default News;
  • 調用組件
    可以是單閉合,也可以是雙閉合。雙閉合方式可以把一些子節點當作屬性(children)傳遞給組件,在組件中可以把傳遞的這些節點放在指定的位置
// index.js
ReactDOM.render(<>
        <Dialog con='嘿嘿嘿'  />
    <Dialog con='呵呵呵' lx={1} >
          <span>1</span>
          <span>2</span>
    </Dialog>
</>, document.getElementById('root'));
// Dialog.js
export default function Dialog(props) {
    let {con, lx = 0, children, style = {}} = props,
        title = lx === 0 ? '系統提示' : '系統警告';
    return <section style={style}>
        <h2>{title}</h2>
        <div>{con}</div>
        {/*把屬性中傳遞的子元素放到組件中的指定位置*/}
        { children }

        {/*也可以基于REACT中提供的專門遍歷CHILDREN的方法來完成遍歷操作*/}
        {
            React.Children.map(children, item => item)
        }
    </section>;
};
  • 靜態組件
    每次調用函數組件,都會重新進行渲染和計算,把渲染后的結果呈現在頁面中,渲染完成后呈現的內容將不再改變,除非重新調用該組件

2.類組件

  • 什么是類組件
    創建一個類,讓其繼承React.Component或者React.PureComponent,此類被稱為類組件
  • 基于狀態管理動態組件:
    1.設置初始狀態值
    2.修改狀態:setState修改組件中的狀態
import React from 'react'

export default class Clock extends React.Component{
  // 調取組件,創建類的一個實例,首先執行constructor,把屬性、上下文等信息傳遞進來
  constructor(props){
    super(props);
    // 如果只寫SUPER():雖然創建實例的時候把屬性傳遞進來了,但是并沒有傳遞父組件,也就是沒有把屬性掛載到實例上,使用THIS.PROPS獲取的結果是UNDEFINED
    // 如果SUPER(PROPS):在繼承父類私有的時候,就把傳遞的屬性掛載到了子類的實例上,CONSTRUCTOR中就可以使用THIS.PROPS了
    console.log(this.props);    // 接收的只讀屬性
    // 創建初始狀態
    this.state = {
      time: new Date().toLocaleString()
    }
  }  
  // render渲染組件的內容  
  render(){
    return <div>
        {this.state.time}
    </div>
  }
  // componentDidMount:生命周期  第一次渲染完
  componentDidMount(){
    setInterval(() => {
            // 修改狀態,并且通知組件重新渲染
            this.setState({
                time: new Date().toLocaleString()
            });
    }, 1000);
}
  • 屬性的操作
    利用第三方插件prop-types可以設置屬性的規則
// test.jsx
import PropTypes from 'prop-types';
...
// 設置默認屬性
static defaultProps = {
    m: 100
};
// 屬性驗證
static propTypes = {
    m: PropTypes.number,
    x: PropTypes.string.isRequired
};
...

// index.js
...
<Clock m={1} x='pass'/>
...
  • 非受控組件
    不受狀態管控的組件(通過ref方式),有時我們會需要直接對某個DOM節點或組件進行操作,而不是通過狀態,此時會運用到非受控組件,對應的概念:受控組件:受狀態管控的組件 => 數據驅動視圖渲染
// 以下是三種使用ref的方法
export default class Input extends React.Component {
    constructor(){
      super();
      this.refObj = React.createRef();  // { current: null }    method 3
    }
    render() {
        return <div>
             <input type="text" ref='inpBox' />      // method 1,不推薦使用
             <input type="text" ref={element => {    // method 2
                // element當前的元素對象
                this.inp = element;
             }} /> 
             <input type="text" ref={ this.refObj } />  // method3
        </div>;
    }
    componentDidMount() {
        this.refs.inpBox.focus();  // method 1,不推薦使用
        this.inp.focus();          // method 2
        this.refObj.current.focus();  // method3
    }
}

3.細節知識點

  • REACT中的事件是合成事件,即所有的事件都是進行事件代理的,而且事件對象也是合成的,故會出現以下情況。解決這一問題的方法有兩種,一是采用bind改變this指向,二是采用ES6的箭頭函數
render(){
  return <div>
    <button onClick={this.handle}>button</button>
  </div>
}
handle(ev){
  console.log(this);    // undefined
  console.log(ev);      // 事件對象
}
<button onClick={this.handle.bind(this)}>button</button>    //method 1
<button onClick={()=>console.log(this)}>button</button>     //method 2
  • 當使用setState進行狀態設置時,即使狀態不發生變化,仍然會觸發render的重新渲染,此時應當考慮對其進行優化,可以在shouldComponentUpdate中進行手動對比設置,也可以直接讓類組件繼承React.PureComponent來自動進行淺對比(引用變化是檢測不出來的)
handle = ev => {
    this.setState({
        // 不管狀態是否改變,都會控制render重新渲染
    });
}
// 手動對比優化,與自動對比同時出現時手動為主
shouldComponentUpdate(nextProps, nextState) {
    // 拿當前的狀態和最新修改的狀態進行對比(淺對比),如果一樣則不渲染,不一樣才進行渲染
    if (this.state.n === nextState.n) {
        return false;
    }
    return true;
} 

// 自動對比
export default class Test extends React.PureComponent {
  ...
}
...
  • setState本身在生命周期函數或者合成事件中執行是異步的
    =>保證REACT生命周期函數執行的順序不會紊亂
    =>保證其實現渲染隊列的機制,可以合并setState后統一處理
export default class Test1 extends React.Component {
   state = {
       n: 0
   };
   render() {
       console.log("render")
       return <div>
           {this.state.n}
           <button onClick={this.handler}>+</button>
       </div>
   }
   handler = ev => {
       this.setState({
           n: this.state.n + 1
       })
       console.log('ok')
   }
}
點擊按鈕后
  • setState在原生事件綁定中和其他異步操作中是同步的
    =>此時失去渲染隊列的效果
export default class Test1 extends React.Component {
    state = {
        n: 0,
        m: 0
    };
    render() {
        console.log('render')
        return <div>
            {this.state.n} === {this.state.m}
            <button onClick={this.handler}>+</button>
        </div>
    }
    handler = ev => {
        setTimeout(()=>{
            this.setState({
                n: 10
            })
            this.setState({
                m:20
            })
            console.log('ok')
        },1000)
        
    }
}
失去渲染隊列處理效果
  • 按理說ES6中的類是不能設置靜態屬性的,但是WEBPACK打包編譯的時候會根據babel-preset-react將其轉換為復合規范的語法
// 以下寫法理應報錯,但是webpack編譯后可正常運行
...
static defaultProps = {
    m: 100
};
static propTypes = {
    m: PropTypes.number,
    x: PropTypes.string.isRequired
};
...
  • 通過onChange事件實現MVVM雙向綁定
...
<input type="text" className='form-control'
      value={text}
      onChange={ev => {
           this.setState({
                text: ev.target.value
           });
}}/>
...

4.生命周期

1.第一次調用組件渲染的周期流程
1.1.給屬性設置默認值(設置默認規則)
1.2.constructor => 設置初始的狀態等
1.3.componentWillMount 第一次掛載之前 => 向服務器發送數據請求
1.4.render 渲染
1.5.componentDidMount 第一次掛載之后 => 把虛擬DOM轉換為真實DOM了,我們可以獲取DOM元素進行操作


2.當組件狀態發生改變 setState
2.1.shouldComponentUpdate(nextProps, nextState) 是否允許當前組件重新渲染(返回TRUE則繼續重新渲染,返回FALSE則停止重新渲染)
2.2.componentWillUpdate(nextProps, nextState) 重新渲染之前
2.3.render重新渲染
2.4.componentWillUpdate 重新渲染之后


3.當組件屬性發生改變:父組件重新傳遞最新的屬性信息
3.1.componentWillReceiveProps(nextProps, nextState) 在接受最新的屬性之前
3.2....(重復2)


4.componentWillUnmount 卸載組件之前

export default class Test extends React.Component {
    constructor(props) {
        super(props);
        console.log('constructor');
        this.state = {
            data: [],
            n: 0
        };
    }

    componentWillMount() {
        console.log('componentWillMount');
        setTimeout(() => {
            this.setState({
                data: [100, 200]
            });
        }, 5000);
    }

    render() {
        console.log('render');
        let { data, n } = this.state;
        return <div>
            {data} === {n}
            <button onClick={() => {
                this.forceUpdate();  <!-- 調用該方法時直接跳過shouldComponentUpdate階段 -->
            }}>強制更新</button>
        </div>;
    }

    componentDidMount() {
        console.log('componentDidMount');
    }

    shouldComponentUpdate(nextProps, nextState) {
        console.log('shouldComponentUpdate', nextProps, nextState);
        // nextProps  nextState 最新要修改的屬性和狀態
        // this.state / this.props 修改之前的
        // this.forceUpdate() 不會執行這個周期函數,會強制更新當前組件
        return true;
    }

    componentWillUpdate() {
        console.log('componentWillUpdate');
    }

    componentDidUpdate() {
        console.log('componentDidUpdate');
    }
} 
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,048評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,414評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,169評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,722評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,465評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,823評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,813評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,000評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,554評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,295評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,513評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,722評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,125評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,430評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,237評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,482評論 2 379

推薦閱讀更多精彩內容

  • 原教程內容詳見精益 React 學習指南,這只是我在學習過程中的一些閱讀筆記,個人覺得該教程講解深入淺出,比目前大...
    leonaxiong閱讀 2,851評論 1 18
  • 作為一個合格的開發者,不要只滿足于編寫了可以運行的代碼。而要了解代碼背后的工作原理;不要只滿足于自己的程序...
    六個周閱讀 8,475評論 1 33
  • 三、React組件 React 組件基本上是由組件的構建方式、組件內的狀態屬性與生命周期方法組成 React.cr...
    梧可奈何閱讀 373評論 0 0
  • 40、React 什么是React?React 是一個用于構建用戶界面的框架(采用的是MVC模式):集中處理VIE...
    萌妹撒閱讀 1,033評論 0 1
  • 1、什么是react React.js 是一個幫助你構建頁面 UI 的庫。React.js 將幫助我們將界面分成了...
    谷子多閱讀 2,565評論 1 13