【轉載】React入門實例教程-讀書筆記

參考了這篇文章:javascript

http://www.ruanyifeng.com/blog/2015/03/react.htmlhtml

其中github 安裝配置見上一篇文章(linkjava

 

1、HTML 模板

使用 React 的網頁源碼,結構大體以下。node

<!DOCTYPE html>
<html>
  <head>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
  </head>
  <body>
    <div id="example"></div>
    <script type="text/babel">
      // ** Our code goes here! **
    </script>
  </body>
</html>

上面有兩個地方須要注意:react

首先,最後一個 <script> 標籤的 type 屬性爲 text/babel 。這是由於 React 獨有的 JSX 語法,跟 JavaScript 不兼容。
凡是使用 JSX 的地方,都要加上 type="text/babel" 。 其次,上面代碼一共用了三個庫: react.js 、react-dom.js 和 Browser.js ,它們必須首先加載。
其中,react.js 是 React 的核心庫,
react-dom.js 是提供與 DOM 相關的功能,
Browser.js 的做用是將 JSX 語法轉爲 JavaScript 語法,
這一步很消耗時間,實際上線的時候,應該將它放到服務器完成。

上面命令能夠將  子目錄的  文件進行語法轉換,轉碼後的文件所有放在  子目錄。$ babel src --out-dir buildsrcjsbuild

babel命令我發如今機器上沒有安裝。須要安裝一下,用了下面兩個命令:jquery

$sudo npm install webpack -g

$sudo npm install webpack babel-loader babel-core babel-preset-es2015 --save-dev -g

可是仍是沒有babel命令行,須要安裝 
$ sudo npm install babel-cli -g

而後就有babel命令行了一剛。webpack

 

在這個目錄添加本身練習代碼的地方:git

/Users/baidu/Documents/Data/Work/Code/Self/react-demosgithub

把build目錄拷過來。web

 

而後在demo1裏面寫一個 index.html :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
        ReactDOM.render(
                <h1>Hello!</h1>,
                document.getElementById('example')
        );
    </script>
</body>
</html>

雙擊在瀏覽器打開,可以看到界面顯示。

試一試babel命令。

建立一個目錄 dist,而後
$ babel . --out-dir dist

可是發現dist目錄沒有變化。看了一下,貌似須要是 js 文件纔可以被轉換。

 

2、ReactDOM.render()

ReactDOM.render 是 React 的最基本方法,用於將模板轉爲 HTML 語言,並插入指定的 DOM 節點。

3、JSX 語法

HTML 語言直接寫在 JavaScript 語言之中,不加任何引號,這就是 JSX 的語法

JSX 的基本語法規則:

遇到 HTML 標籤(以 < 開頭),就用 HTML 規則解析;

遇到代碼塊(以 { 開頭),就用 JavaScript 規則解析。

關於上面的內容,又寫了一段代碼(參考demo2):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
        var names = ['a', 'b', 'c'];

        ReactDOM.render(
                <div>
                    {
                        names.map(function (name) {
                            return <div> Hello {name}!</div>
                        })
                    }
                </div>,
                document.getElementById('example')
        )

    </script>
</body>
</html>

注意,以上的語句都沒有加分號,其實js是不須要有分號;的。

雙擊在瀏覽器打開後,可以看到:

Hello a!
Hello b!
Hello c!

以上的代碼中,數組是經過map來進行映射和執行的。而若是把數組直接放在jsx模板中,數組的內容會直接展開。

以下(參考了demo03):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
        var arr = [
                <h1>Hello,</h1>,
                <h2>Here!</h2>
        ]

        ReactDOM.render(
                <div>{arr}</div>,
                document.getElementById('example')
        )

    </script>
</body>
</html>

4、組件

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

下面的代碼生成一個組件(使用React.createClass,參考demo04):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
        var Hello = React.createClass({
            render:function () {
                return <h1>Hello {this.props.name}</h1>
            }
        })

        ReactDOM.render(
                <Hello name="myname"/>,
                document.getElementById('example')
        )

    </script>
</body>
</html>

瀏覽器界面顯示:

Hello myname

模板插入 <Hello /> 時,會自動生成 Hello 的一個實例(下文的"組件"都指組件類的實例)。

全部組件類都必須有本身的 render 方法,用於輸出組件。

組件類的第一個字母必須大寫,不然會報錯。

另外,組件類頂層標籤個數只能是一個,不能有多個頂層標籤,(非頂層標籤隨意),不然也會報錯。

組件的用法與原生的 HTML 標籤徹底一致,能夠任意加入屬性,組件的屬性能夠在組件類的 this.props 對象上獲取。

添加組件屬性,須要注意的是,class 屬性須要寫成 className ,for 屬性須要寫成 htmlFor ,由於 class 和 for 是 JavaScript 的保留字。

 

5、this.props.children

this.props 對象的屬性與組件的屬性一一對應,可是有一個例外,就是 this.props.children 屬性。它表示組件的全部子節點。

寫一段代碼以下(參考demo5):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
        var Hello = React.createClass({
            render:function () {
                return (<ol>{
                    React.Children.map(this.props.children,
                            function (child) {
                            return <li>
                                {child}
                            </li>
                    })
                }</ol>)
            }
        })

        ReactDOM.render(
                <Hello>
                    <span>hello</span>
                    <span>world</span>
                </Hello>,
                document.getElementById('example')
        )

    </script>
</body>
</html>

頁面代碼,加上了li:

<ol data-reactroot=""><li><span>hello</span></li><li><span>world</span></li></ol>

props.children使用注意點以下:

this.props.children 的值有三種可能:
若是當前組件沒有子節點,它就是 undefined ;
若是有一個子節點,數據類型是 object ;
若是有多個子節點,數據類型就是 array 。
因此,處理 this.props.children 的時候要當心。

React 提供一個工具方法 React.Children 來處理 this.props.children 。
咱們能夠用 React.Children.map 來遍歷子節點,而不用擔憂 this.props.children 的數據類型是 undefined 仍是 object。
更多的 React.Children 的方法,能夠參考官方文檔。
https://facebook.github.io/react/docs/top-level-api.html#react.children

6、PropTypes

組件類的PropTypes屬性,就是用來驗證組件實例的屬性是否符合要求。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
        var Hello = React.createClass({
            propTypes: {
                title: React.PropTypes.string.isRequired,
            },
            render: function () {
                return <h1> {this.props.title} </h1>
            }
        })

        var data = 123;
        ReactDOM.render(
                <Hello title={data}/>,
                document.getElementById('example')
        )

    </script>
</body>
</html>

運行時,會發現報錯:

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

另外,能夠用getDefaultProps設置props的默認值:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
        var Hello = React.createClass({
            getDefaultProps: function () {
                return {
                    title: "Hello"
                }
            },
            propTypes: {
                title: React.PropTypes.string.isRequired,
            },
            render: function () {
                return <h1> {this.props.title} </h1>
            }
        })

        var data = 123;
        ReactDOM.render(
                <Hello/>,
                document.getElementById('example')
        )

    </script>
</body>
</html>

瀏覽器顯示:

Hello

7、獲取真實的DOM節點

 組件並非真實的 DOM 節點,而是存在於內存之中的一種數據結構,叫作虛擬 DOM (virtual DOM)。

只有當它插入文檔之後,纔會變成真實的 DOM 。根據 React 的設計,全部的 DOM 變更,都先在虛擬 DOM 上發生,
而後再將實際發生變更的部分,反映在真實 DOM上,這種算法叫作 DOM diff ,它能夠極大提升網頁的性能表現。

DOM diff的算法能夠詳見:link

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
        var Hello = React.createClass({
            handleClick: function () {
                this.refs.myTextInput.focus();
            },

            render: function () {
                return (
                     <div>
                         <input type="text" ref="myTextInput"/>
                         <input type="button" value="Focus" onClick={this.handleClick}/>
                     </div>
                )
            }
        })

        var data = 123;
        ReactDOM.render(
                <Hello/>,
                document.getElementById('example')
        )

    </script>
</body>
</html>

爲了作到這一點,文本輸入框必須有一個 ref 屬性,而後 this.refs.[refName] 就會返回這個真實的 DOM 節點。

須要注意的是,因爲 this.refs.[refName] 屬性獲取的是真實 DOM ,因此必須等到虛擬 DOM 插入文檔之後,才能使用這個屬性,不然會報錯。
上面代碼中,經過爲組件指定 Click 事件的回調函數,確保了只有等到真實 DOM 發生 Click 事件以後,纔會讀取 this.refs.[refName] 屬性。
React 組件支持不少事件,除了 Click 事件之外,還有 KeyDown 、Copy、Scroll 等,完整的事件清單請查看官方文檔。
https://facebook.github.io/react/docs/events.html#supported-events

8、this.state

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

看以下代碼,demo8:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
        var Hello = React.createClass({
            getInitialState: function () {
               return {liked: false}
            },

            handleClick: function (event) {
                this.setState({liked: !this.state.liked})
            },

            render: function () {
                var text = this.state.liked ? 'like' : 'haven\'t liked';
                return (
                     <p onClick={this.handleClick}>
                         You {text} this. Click to toggle.
                     </p>
                )
            }
        })

        var data = 123;
        ReactDOM.render(
                <Hello/>,
                document.getElementById('example')
        )

    </script>
</body>
</html>

React 的一大創新,就是將組件當作是一個狀態機,一開始有一個初始狀態,而後用戶互動,致使狀態變化,從而觸發從新渲染 UI。

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

9、表單

文本輸入框的值,不能用 this.props.value 讀取,而要定義一個 onChange 事件的回調函數,經過 event.target.value 讀取用戶輸入的值。

textarea 元素、select元素、radio元素都屬於這種狀況,更多介紹請參考官方文檔

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
        var Hello = React.createClass({
            getInitialState: function () {
               return {value: 'Hello!'}
            },

            handleChange: function (event) {
                this.setState({value: event.target.value})
            },

            render: function () {
                var text = this.state.value;
                return (
                     <div>
                         <input type="text" value={text} onChange={this.handleChange}/>
                         <p>{text}</p>
                     </div>
                )
            }
        })

        var data = 123;
        ReactDOM.render(
                <Hello/>,
                document.getElementById('example')
        )

    </script>
</body>
</html>

以上參考demo09。瀏覽器頁面以下:

hidanfeingd,aennga
hidanfeingd,aennga

上面文本框和下面的文本內容是同步的。

10、組件的生命週期

組件的生命週期分紅三個狀態:

Mounting:已插入真實 DOM
Updating:正在被從新渲染
Unmounting:已移出真實 DOM

 React 爲每一個狀態都提供了兩種處理函數,will 函數在進入狀態以前調用,did 函數在進入狀態以後調用,三種狀態共計五種處理函數。

componentWillMount()
componentDidMount()
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
componentWillUnmount()

此外,React 還提供兩種特殊狀態的處理函數。

componentWillReceiveProps(object nextProps):已加載組件收到新的參數時調用
shouldComponentUpdate(object nextProps, object nextState):組件判斷是否從新渲染時調用

須要找時間詳細閱讀一下官方文檔:link 

The Component Lifecycle

 

Mounting

 

These methods are called when an instance of a component is being created and inserted into the DOM:

 

 

Updating

 

An update can be caused by changes to props or state. These methods are called when a component is being re-rendered:

 

 

Unmounting

 

This method is called when a component is being removed from the DOM:

 

 

Other APIs

 

Each component also provides some other APIs:

 

 

Class Properties

 

 

Instance Properties

 

參考Demo10,寫了一個例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
        var Hello = React.createClass({
            getInitialState: function () {
               return {opacity: 1.0}
            },

            componentDidMount: function () {
                this.timer = setInterval(function () {
                    var opacity = this.state.opacity;
                    opacity -= .05;
                    if (opacity < 0.1) {
                        opacity = 1.0;
                    }
                    this.setState({
                        opacity: opacity
                    })
                }.bind(this), 100)
            },

            render: function () {
                return (
                     <div style={{opacity: this.state.opacity}}>
                         Hello {this.props.name}
                     </div>
                )
            }
        })

        var data = 123;
        ReactDOM.render(
                <Hello name="Bill"/>,
                document.getElementById('example')
        )

    </script>
</body>
</html>

界面上面會有一行字,深淺逐漸變化。

經過 componentDidMount 方法設置一個定時器,每隔100毫秒,就從新設置組件的透明度,從而引起從新渲染。

另外,組件的style屬性的設置方式也值得注意:

不能寫成
style="opacity:{this.state.opacity};"
而要寫成 style={{opacity: this.state.opacity}} 這是由於 React 組件樣式是一個對象,因此第一重大括號表示這是 JavaScript 語法,第二重大括號表示樣式對象。
參考: https://facebook.github.io/react/tips/inline-styles.html

11、Ajax

組件的數據來源,一般是經過 Ajax 請求從服務器獲取,能夠使用 componentDidMount 方法設置 Ajax 請求,

等到請求成功,再用 this.setState 方法從新渲染 UI。

 

開始沒有任何反應,應該是跨域了。結果不是,是缺了jquery的庫。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
    <script src="../build/jquery.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
        var Hello = React.createClass({
            getInitialState: function () {
               return {
                   username: '',
                   lastGistUrl: ''
               }
            },

            componentDidMount: function () {
                //alert("hihi")
                $.get(this.props.source, function (result) {
                    //alert(result);
                    var lastGist = result[0];


                    if (this.isMounted()) {
                        this.setState({
                            username: lastGist.owner.login,
                            lastGistUrl: lastGist.html_url
                        })
                    }
                }.bind(this))
            },

            render: function () {
                return (
                     <div>
                         Hello {this.state.username}
                         <a href={this.state.lastGistUrl}>here</a>
                     </div>
                )
            }
        })

        ReactDOM.render(
                <Hello source="https://api.github.com/users/octocat/gists"/>,
                document.getElementById('example')
        )

    </script>
</body>
</html>

奇怪的是,我訪問其餘url,老是存在跨域問題,訪問api.github就不會出現這樣的問題。。

 

而且能夠直接在html標籤裏面用 getJSON,而後根據狀態來處理,以下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
    <script src="../build/jquery.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
        var Hello = React.createClass({
            getInitialState: function () {
               return {
                   loading: true,
                   error: null,
                   data: null
               }
            },

            componentDidMount: function () {
                this.props.promise.then( value => this.setState({loading: false, data: value}), error => this.setState({loading: false, error: error}) )
            },

            render: function () {
                if (this.state.loading) {
                    return <span> Loading... </span>
                }
                else if (this.state.error !== null) {
                    return <span>Error: {this.state.error}</span>
                }
                else {
                    var repos = this.state.data.items;
                    var repoList = repos.map(
                            function (repo, index) {
                                return (
                                        <li key={index}>
                                            <a href={repo.html_url}>{repo.name}</a>
                                            ({repo.stargazers_count} stars) <br/>
                                            {repo.description}
                                        </li>
                                )
                            }
                    )
                    return (
                            <main>
                                <h1>Most Popular Javascript Project in Github</h1>
                                <ol>{repoList}</ol>
                            </main>
                    )
                }
            }
        })

        ReactDOM.render(
                <Hello promise={$.getJSON('https://api.github.com/search/repositories?q=javascript&sort=stars')}/>,
                document.getElementById('example')
        )

    </script>
</body>
</html>

瀏覽器裏面能夠看到,先是loading,而後有下面的結果:

 

 

最後,還有一個demo 13,是介紹react server,首屏渲染的。

安裝方法,先到demo13目錄裏:

# install the dependencies in demo13 directory
$ npm install

# translate all jsx file in src subdirectory to js file
$ npm run build

# launch http server
$ node server.js

 

而後 localhost:3000 能訪問,可是貌似有一些界面的問題。有機會再看。

相關文章
相關標籤/搜索