React Native開發之必備React基礎

爲了幫助你們快速上手React Native開發,在這本節中將向你們介紹開發React Native所須要的一些React必備基礎知識javascript

概述

本節課將從React的特色、如何使用React、JSX語法,而後會對組件(Component)以及組件的屬性(props)、狀態(state)、生命週期等方面進行講解。html

經過本節課程能學到什麼?

  • 對React有個全面的認識;
  • 熟悉JSX基本語法;
  • 瞭解組件結構;
  • 熟悉組件的生命週期;
  • 學會使用props;
  • 學會使用state;
  • 熟悉自定義組件;

React是什麼?

React 是 Facebook 推出的開源 JavaScript Library,它是一個用於組建用戶界面的JavaScript庫,讓你以更簡單的方式來建立交互式用戶界面,它的出現讓許多革新性的 Web 觀念開始流行起來,例如:Virtual DOM、Component,聲明式渲染等。java

聲明式與命令式node

命令式編程:命令「機器」如何去作事情(how),這樣無論你想要的是什麼(what),它都會按照你的命令實現。
聲明式編程:告訴「機器」你想要的是什麼(what),讓機器想出如何去作(how)。
複製代碼

演示react

  1. 當數據改變時,React將高效的更新和渲染須要更新的組件。聲明式視圖使你的代碼更可預測,更容易調試。
  2. 構建封裝管理本身的狀態的組件,而後將它們組裝成複雜的用戶界面。因爲組件邏輯是用JavaScript編寫的,而不是模板,因此你能夠輕鬆地經過您的應用程序傳遞豐富的數據,並保持DOM狀態。
  3. 一次學習隨處可寫,學習React,你不只能夠將它用於Web開發,也能夠用於React Native來開發Android和iOS應用。

如何使用?

構建一個新的 React 單頁應用,能夠經過Create React App來完成。它能夠幫助你配置開發環境,以便你可使用最新的 JavaScript 特性,還能提供一個友好的開發體驗,併爲生產環境優化你的應用。git

npm install -g create-react-app
create-react-app my-app
cd my-app
npm start
複製代碼
"dependencies": {
    "react": "^16.6.3",//是 React 的核心庫
    "react-dom": "^16.6.3",//提供與 DOM 相關的功能
    "react-scripts": "2.1.1"//create-react-app 的一個核心包,一些腳本和工具的默認配置都集成在裏面
  },
複製代碼

ReactDOM.render

ReactDOM.render(element, container[, callback])github

渲染一個 React 元素到由 container 提供的 DOM 中,而且返回組件的一個 引用(reference) (或者對於 無狀態組件 返回 null )。算法

JSX

JSX 是一個看起來很像 XML 的 JavaScript 語法擴展。 每個XML標籤都會被JSX轉換工具轉換成純JavaScript代碼,使用JSX,組件的結構和組件之間的關係看上去更加清晰。 JSX並非React必須使用的,但React官方建議咱們使用 JSX , 由於它能定義簡潔且咱們熟知的包含屬性的樹狀結構語法。npm

Usage:編程

React.render(//使用JSX
    <div>
        <div>
            <div>content</div>
        </div>
    </div>,
    document.getElementById('example')
);
React.render(//不使用JSX
    React.createElement('div', null,
        React.createElement('div', null,
            React.createElement('div', null, 'content')
        )
    ),
    document.getElementById('example')
);
複製代碼

createElement

React.createElement(
  type,
  [props],
  [...children]
)
複製代碼

根據給定的類型建立並返回新的 React element 。參數type既能夠是一個html標籤名稱字符串(例如'div' 或 'span' ),也能夠是一個 React component 類型(一個類或一個函數)。

React.createElement(Hello, {toWhat: 'World'}, 'hello'),
//等價於 <Hello toWhat="World">hello</Hello>,

複製代碼

HTML標籤 與 React組件 對比

React 能夠渲染 HTML 標籤 (strings) 或 React 組件 (classes)。 要渲染 HTML 標籤,只需在 JSX 裏使用小寫字母開頭的標籤名。

var myDivElement = <div className="foo" />;
React.render(myDivElement, document.root);
複製代碼

要渲染 React 組件,只需建立一個大寫字母開頭的本地變量。

var MyComponent = ...;
var myElement = <MyComponent someProperty={true} />;
React.render(myElement, document.body);
複製代碼

提示:

  • React 的 JSX 里約定分別使用首字母大、小寫來區分本地組件的類和 HTML 標籤。
  • 因爲 JSX 就是 JavaScript,一些標識符像 class 和 for 不建議做爲 XML 屬性名。做爲替代, React DOM 使用 className 和 htmlFor 來作對應的屬性。

JavaScript 表達式

屬性表達式

要使用 JavaScript 表達式做爲屬性值,只需把這個表達式用一對大括號 {} 包起來,不要用引號 ""

// 輸入 (JSX):
var person = <Person name={window.isLoggedIn ? window.name : ''} />;
// 輸出 (JS):
var person = React.createElement(
  Person,
  {name: window.isLoggedIn ? window.name : ''}
);
複製代碼

子節點表達式

一樣地,JavaScript 表達式可用於描述子結點:

// 輸入 (JSX):
var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>;
// 輸出 (JS):
var content = React.createElement(
  Container,
  null,
  window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login)
);
複製代碼

註釋

JSX 裏添加註釋很容易,它們只是 JS 表達式而已。你只須要在一個標籤的子節點內(非最外層)用 {} 包圍要註釋的部分。

class ReactDemo extends Component {
  render() {
    return (
      <View style={styles.container}>
        {/*標籤子節點的註釋*/}
        <Text style={styles.welcome} //textAlign='right' textShadowColor='yellow' /*color='red' textShadowRadius='1'*/ >
          React Native!
        </Text>
      </View>
    );
  }
}
複製代碼

心得:在標籤節點之外註釋,和一般的註釋是同樣的,多行用「/**/」 單行用「//」;

JSX延展屬性

不要試圖去修改組件的屬性

不推薦作法:

var component = <Component />;
  component.props.foo = x; // 不推薦
  component.props.bar = y; // 不推薦
複製代碼

這樣修改組件的屬性,會致使React不會對組件的屬性類型(propTypes)進行的檢查。從而引起一些預料以外的問題。

推薦作法:

var component = <Component foo={x} bar={y} />;
複製代碼

延展屬性(Spread Attributes)

你可使用 JSX 的新特性 - 延展屬性:

var props = {};
  props.foo = x;
  props.bar = y;
  var component = <Component {...props} />;
複製代碼

傳入對象的屬性會被複制到組件內。

它能被屢次使用,也能夠和其它屬性一塊兒用。注意順序很重要,後面的會覆蓋掉前面的。

var props = { foo: 'default' };
  var component = <Component {...props} foo={'override'} />;
  console.log(component.props.foo); // 'override'
複製代碼

上文出現的...標記被叫作延展操做符(spread operator)已經被 ES6 數組 支持。

www.devio.org/2018/09/09/…

Component

React 容許將代碼封裝成組件(component),而後像插入普通 HTML 標籤同樣,在網頁中插入這個組件。

class Hello extends React.Component{
    render() {
        return <h1>Hello {this.props.name}</h1>;
    }
}
ReactDOM.render(
  <Hello name="John" />,
  document.getElementById('example')
);
複製代碼

上面代碼中,變量 HelloMessage 就是一個組件類。模板插入 <HelloMessage />時,會自動生成 HelloMessage 的一個實例。全部組件類都必須有本身的 render 方法,用於輸出組件。

注意

  • 組件類的第一個字母必須大寫
  • 組件類只能包含一個頂層標籤? 演示

組件的屬性(props)

咱們能夠經過this.props.xx的形式獲取組件對象的屬性,對象的屬性能夠任意定義,但要避免與JavaScript關鍵字衝突。

遍歷對象的屬性:

this.props.children會返回組件對象的全部屬性。 React 提供一個工具方法 React.Children 來處理 this.props.children 。咱們能夠用 React.Children.mapReact.Children.forEach 來遍歷子節點。

React.Children.map

React.Children.map(children, function[(thisArg)])
複製代碼

在包含在 children 裏的每一個子級上調用函數,調用的函數的 this 設置爲 thisArg 。若是 children 是一個嵌套的對象或數組,它將被遍歷。若是 children 是 null 或 undefined ,返回 null 或 undefined 而不是一個空數組。

React.Children.forEach

React.Children.forEach(children, function[(thisArg)])
複製代碼

Usage:

class NotesList extends React.Component{
    render(){
        return (
            <ol> { React.Children.map(this.props.children,(child)=> { return <h1>{child}</h1>; }) } </ol>
        );
    }
}
ReactDOM.render(<NotesList> <span>hello</span> <span>world</span> </NotesList>, document.getElementById('root'));
複製代碼

演示

[PropTypes]

組件的屬性能夠接受任意值,字符串、對象、函數等等均可以。有時,咱們須要一種機制,驗證別人使用組件時,提供的參數是否符合要求。 組件類的PropTypes屬性,就是用來驗證組件實例的屬性是否符合要求。

React.PropTypes 從 React v15.5開始被移入了prop-types,使用時須要留意;

import  PropTypes from 'prop-types'
class MyTitle extends React.Component{
    static propTypes={
        title: PropTypes.string.isRequired,
    };
    render() {
        return <h1> title:{this.props.title} </h1>;
    }
}
ReactDOM.render(<MyTitle />, document.getElementById('root'));
複製代碼

上面的Mytitle組件有一個title屬性。PropTypes 告訴 React,這個 title 屬性是必須的,並且它的值必須是字符串。如今,咱們設置 title 屬性的值是一個數值。

var data = 123;
ReactDOM.render(
  <MyTitle title={data} />,
  document.body
);
複製代碼

這樣一來,title屬性就通不過驗證了。控制檯會顯示一行錯誤信息。

Warning: Failed propType: Invalid prop `title` of type `number` supplied to `MyTitle`, expected `string`.

更多的PropTypes設置,能夠查看官方文檔

默認屬性

此外,能夠經過defaultProps用來設置組件屬性的默認值。

class MyTitle extends React.Component{
    static defaultProps={
        shortName:'MyTitle'
    };
    render() {
        return <h1> {this.props.shortName}</h1>;
    }
}
ReactDOM.render(<MyTitle/>, document.getElementById('root'));
複製代碼

上面代碼會輸出"MyTitle"

ref 屬性(獲取真實的DOM節點)

組件並非真實的 DOM 節點,而是存在於內存之中的一種數據結構,叫作虛擬 DOM (virtual DOM)。只有當它插入文檔之後,纔會變成真實的 DOM 。根據 React 的設計,全部的 DOM 變更,都先在虛擬 DOM 上發生,而後再將實際發生變更的部分,反映在真實 DOM上,這種算法叫作 DOM diff ,它能夠極大提升網頁的性能表現。

可是,有時須要從組件獲取真實 DOM 的節點,這時就要用到 ref 屬性。

class Alert extends React.Component {
    showAlert(message) {
        alert(`Debug:${message}`);
    }

    render() {
        return null;
    }
}

class MyTitle extends React.Component {
    onClick = () => {
        this.refs.alert.showAlert('MyTitle');
    };

    render() {
        return <div>
            <h1 onClick={this.onClick}>Click me</h1>
            <Alert ref='alert'/>
        </div>;
    }
}

ReactDOM.render(<MyTitle/>, document.getElementById('root'));
複製代碼

上面代碼中,組件 MyTitle 的子節點有一個Alert組件,爲了調用這個組件提供的方法,這時就必須獲取真實的 DOM 節點,虛擬 DOM 是拿不到用戶輸入的。爲了作到這一點,咱們在使用這個組件的時候必須爲其設置一個ref屬性,而後 this.refs.[refName] 就會返回這個真實的 DOM 節點。

須要注意的是,因爲 this.refs.[refName] 屬性獲取的是真實 DOM ,因此必須等到虛擬 DOM 插入文檔之後,才能使用這個屬性,不然會報錯。上面代碼中,經過爲組件指定 Click 事件的回調函數,確保了只有等到真實 DOM 發生 Click 事件以後,纔會讀取 this.refs.[refName] 屬性。

React 組件支持不少事件,除了 Click 事件之外,還有 KeyDown 、Copy、Scroll 等,完整的事件清單請查看官方文檔

心得:ref屬性在開發中使用頻率很高,使用它你能夠獲取到任何你想要獲取的組件的對象,有了這個對象你就能夠靈活地作不少事情,好比:讀寫對象的變量,甚至調用對象的函數。

state

上文講到了props,組件會根據props的變化來進行渲染,但組件沒法改變自身的props,那麼組件爲了實現交互,可使用組件的 state 。state 是組件私有的,能夠經過state={}方式初始化,經過調用 this.setState() 來改變它。當 state 更新以後,組件就會從新渲染本身。

render() 方法依賴於 this.props 和 this.state ,框架會確保渲染出來的 UI 界面老是與輸入( this.props 和 this.state )保持一致。

初始化state

能夠經過一下兩種方式來初始化state,在組件的生命週期中僅執行一次,用於設置組件的初始化 state 。

constructor(props){
    super(props);
    this.state={
        name:''
    }
}
//or
state={
    name:''
}
複製代碼

更新 state

經過this.setState()方法來更新state,調用該方法後,React會從新渲染相關的UI。 this.setState({favorite:!this.state.favorite});

Usage:

class FavoriteButton extends React.Component{
   state={
       favorite:false
   };
    handleClick=()=>{
        this.setState({favorite:!this.state.favorite});
    };
    render(){
        const text=this.state.favorite? 'favorite':'un favorite';
        return (
            <h1 onClick={this.handleClick}> You {text} this. Click to toggle. </h1>
        );
    }
}
複製代碼

上面代碼是一個 FavoriteButton 組件,它的經過 state={}初始狀態,也就是一個對象,這個對象能夠經過 this.state 屬性讀取。當用戶點擊組件,致使狀態變化,this.setState 方法就修改狀態值,每次修改之後,自動調用 this.render 方法,再次渲染組件。

心得:因爲 this.props 和 this.state 都用於描述組件的特性,可能會產生混淆。一個簡單的區分方法是,this.props 表示那些本組件沒法改變的特性,而 this.state 是會隨着用戶互動而產生變化的特性。

組件的生命週期

在iOS中UIViewController提供了(void)viewWillAppear:(BOOL)animated, - (void)viewDidLoad,(void)viewWillDisappear:(BOOL)animated等生命週期方法,在Android中Activity則提供了onCreate(),onStart(),onResume(),onPause(),onStop(),onDestroy()等生命週期方法,這些生命週期方法描述了一個界面從建立到銷燬的一輩子。

那麼在React 中組件(Component)也是有本身的生命週期方法的。

react-lifecycle-methods-diagram

演示

[組件的生命週期分紅三個時期:

  • Mounting:建立時
  • Updating:更新時
  • Unmounting:卸載時

不安全的方法

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

使用這些生命週期方法一般會致使錯誤和不一致,所以未來會被棄用。在新的React版本中他們被標記爲UNSAFE。

static-lifecycle-methods

Mounting(裝載)

constructor()

constructor(props)
複製代碼

React組件的構造函數將會在裝配以前被調用。當爲一個React.Component子類定義構造函數時,你應該在任何其餘的表達式以前調用super(props)。不然,this.props在構造函數中將是未定義,並可能引起異常。

構造函數是初始化狀態的合適位置。若你不初始化狀態且不綁定方法,那你也不須要爲你的React組件定義一個構造函數。

static getDerivedStateFromProps()

static getDerivedStateFromProps(nextProps, prevState)
複製代碼

組件實例化後和接受新屬性時將會調用getDerivedStateFromProps。它應該返回一個對象來更新狀態,或者返回null來代表新屬性不須要更新任何狀態。

注意,若是父組件致使了組件的從新渲染,即便屬性沒有更新,這一方法也會被調用。若是你只想處理變化,那麼能夠經過比較新舊值來完成。

調用this.setState() 一般不會觸發 getDerivedStateFromProps()。

render

ReactComponent render()
複製代碼

render() 方法是必須的。

當被調用時,其會檢查this.props 和 this.state並返回如下類型中的一個:

  • React元素。 一般是由 JSX 建立。該元素多是一個原生DOM組件的表示,如
    ,或者是一個你定義的複合組件。
  • 字符串和數字。 這些將被渲染爲 DOM 中的 text node。
  • Portals。 由 ReactDOM.createPortal 建立。
  • null。 什麼都不渲染。
  • 布爾值。 什麼都不渲染。(一般存在於 return test && 寫法,其中 test 是布爾值。)

返回null 或 false時,ReactDOM.findDOMNode(this) 將返回 null。

render()函數應該是純粹的,也就是說該函數不修改組件的 state,每次調用都返回相同的結果,不讀寫 DOM 信息,也不和瀏覽器交互(例如經過使用 setTimeout)。若是須要和瀏覽器交互,在 componentDidMount() 中或者其它生命週期方法中作這件事。保持 render() 純粹,可使服務器端渲染更加切實可行,也使組件更容易被理解。

提示:若 shouldComponentUpdate()返回false,render()函數將不會被調用。

componentDidMount()

componentDidMount()
複製代碼

componentDidMount()在組件被裝配後當即調用,一般在該方法中進行一些初始化操做。·初始化時須要DOM節點的操做能夠放到這裏進行`。若你須要從遠端加載數據,這是一個適合實現網絡請求的地方。在該方法裏設置狀態將會觸發重渲。

這一方法是一個發起任何訂閱的好地方。若是你這麼作了,別忘了在componentWillUnmount()退訂。

另外,在這個方法中調用setState()將會觸發一次額外的渲染,可是它將在瀏覽器刷新屏幕以前發生。這保證了即便render()將會調用兩次,但用戶不會看到中間狀態。

Updating (更新)

shouldComponentUpdate

shouldComponentUpdate(nextProps, nextState)
複製代碼

在接收到新的 props 或者 state,將要渲染以前調用,以讓React知道當前狀態或屬性的改變是否不影響組件的輸出。

該方法在初始化渲染的時候不會調用,在使用 forceUpdate 方法的時候也不會。若是肯定新的 props 和 state 不須要從新渲染,則此處應該 返回 false。

心得:重寫次方你能夠根據實際狀況,來靈活的控制組件當 props 和 state 發生變化時是否要從新渲染組件。

getSnapshotBeforeUpdate

getSnapshotBeforeUpdate(prevProps, prevState)
複製代碼

getSnapshotBeforeUpdate()在最新的渲染輸出提交給DOM前將會當即調用。它讓你的組件能在當前的值可能要改變前得到它們。這一輩子命週期返回的任何值將會 做爲參數被傳遞給componentDidUpdate()。

componentDidUpdate

componentDidUpdate(prevProps, prevState, snapshot)
複製代碼

在組件的更新已經同步到 DOM 中以後馬上被調用。

該方法不會在初始化渲染的時候調用。使用該方法能夠在組件更新以後操做 DOM 元素。

Unmounting(移除)

componentWillUnmount

componentWillUnmount()
複製代碼

在組件從 DOM 中移除的時候馬上被調用。

在該方法中執行任何須要的清理,好比無效的定時器,或者清除在 componentDidMount 中建立的 DOM 元素。

參考

相關文章
相關標籤/搜索