react - 基礎入門

github倉庫

github中包含了所有的源碼,麻煩在各位fork的同時,給小的賞一顆star,謝謝!

https://github.com/Rynxiao/react-newer

JSX語法

const element = <h1>Hello, world!</h1>;

This funny tag syntax is neither a string nor HTML.

It is called JSX, and it is a syntax extension to JavaScript. We recommend using it with React to describe what the UI should look like. JSX may remind you of a template language, but it comes with the full power of JavaScript.

JSX produces React “elements”.


意思就是jsx語句既不是一個字符串,同時也不是HTML,它是javascript的擴展。沒錯,它是一個js文件,只是可以在js文件中直接寫html標籤,不用加任何標籤。例如:

var names = ['Alice', 'Emily', 'Kate'];

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

規則:遇到[HTML]以(<)開頭,遇到代碼塊以({)開頭

官網例子下載地址: http://reactjs.cn/react/downloads/react-15.3.1.zip

Hello World - 編寫一個簡單程序

  • 直接引入方式, USE CDN

<div id="root"></div>
<script src="https://unpkg.com/[email protected]/dist/react.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.min.js"></script>
<script type="text/babel">
    ReactDOM.render(
        <h1>Hello world</h1>,
        document.getElementById("root")
    );
</script>

// 引入browser.js是因爲瀏覽器默認是不識別以jsx結尾的文件
// 因此需要使用browser.js進行轉義
// 注意,此時script的類型爲text/babel

// 如果沒有引入browser.js,可以這麼寫(其實就相當於轉義之後的寫法):
<script>
    function ExampleApplication() {
        // this equals to React.createElement('p', null, 'Hello world');
        return React.DOM.p(null, "Hello world");
    }

    // or React.createElement(ExampleApplication);
    var ExampleApplicationFactory = React.createFactory(ExampleApplication);

    ReactDOM.render(
        React.createElement(ExampleApplication),
        document.getElementById('root')
    );
</script>
  • 使用[babel]提前編譯

提前將[jsx]文件編譯成[js]文件,在[html]文件中單獨引入

注意: babel 6.0 之前的編譯需要全局安裝 babel, 而高於 6.0 版本的需要全局安裝babel-cli,具體例子如下:

// With Babel lower than 6.0

npm install -g babel
cd basic-jsx-precompile/
babel example.js --out-dir=build

// With Babel 6.0 or higher

npm install -g babel-cli
cd basic-jsx-precompile/
npm install babel-preset-react
babel example.js --presets react --out-dir=build
  • 使用[webpack]或者[Browserify]之類的編譯工具編譯([Browserify]沒有研究過,下面主要介紹一下簡單的[webpack]配置,可以參看之前的文檔webpack

使用[webpack]需要配置[webpack.config.js]文件,具體如下:

module.exports = {
    entry : {
        app : ['webpack.js']
    },
    output : {
        path : './assets/',
        filename : '[name].bundle.js',
        publicPath : './assets/'
    },
    module : {
        loaders : [
            // npm install babel-loader
            { test : /\.js|\.jsx$/, loader : 'babel' },
            { test : /\.css$/, loader : 'style!css' }
        ]
    }
};

生成的編譯文件爲[app.bundle.js],可以直接在[html]文件中引入

webpack

array && object

react中可以直接渲染數組,數組元素可以是簡單的字符串,也可以是jsx語法中的元素定義,同時還可以使用Array.prototype.map來遍歷數組,代碼如下:

React.createClass({
    render() {

        let arr = ['Lily', 'John', 'Ryn', "Harry"],
            arr2 = [<h1>Lily</h1>, <h1>John</h1>, <h1>Ryn</h1>, <h1>Harry</h1>];

        return (
            <div className="App">
                <p>1. 直接使用,會直接輸出</p>
                {arr}
                <p>2. 數組中的元素可以是jsx語法中的元素</p>
                {arr2}
                <p>2. 可使用 [Array.prototype.map] 函數遍歷</p>
                <ul>
                    {
                        arr.map((a , i) => {
                            return <li key={'a'+i}>{`Hello, I'm ${a}`}</li>
                        })
                    }
                </ul>
            </div>
        );
    }
});

array

對象使用.來使用,如:

let obj = {name : 'Ryn', 'message' : 'hello'};

return (
    <div className="App">
        My name is {obj.name}, and I say {obj.message}!
    </div>
);

this.props

[this.props]中的屬性對應從組件傳過來的屬性,例如<Hello sub="world" />,那麼在Hello組件中就可以使用this.props.sub來獲取這個值。例如:

/**
 * 調用方式
 * <PropsExample name="ryn" message="hello" />
 */

'use strict';

import React from 'react';

export default React.createClass({
    render() {
        return (
            <div className="App">
                My name is {this.props.name}, and I say {this.props.message}!
            </div>
        );
    }
});

注意特殊的[this.props.children],它表示組件的子節點

但是[this.props.children]可能會有三種類型,當組件下沒有子節點的時候,它的值類型是undefined,有一個子節點時,它的類型是Object,當有超過兩個子節點時,它的類型是Array,例如:

/**
 * 調用方式
 * <NodeList>
 *     <span>I'm a NodeList Component's child.</span>
 *     <span>I'm a NodeList Component's child.</span>
 * </NodeList>
 */

'use strict';

import React from 'react';

export default React.createClass({
    render() {
        console.log("this.props.children type", typeof this.props.children);
        console.log("this.props.children type Array?", Object.prototype.toString.call(this.props.children));
        return (
            <ol>
                {
                    React.Children.map(this.props.children, function (child) {
                        return <li>{child}</li>;
                    })
                }
            </ol>
        );
    }
});

如下調用時:

<NodeList />

截圖:

none-child

<NodeList>
    <span>I'm a NodeList Component's child.</span>
</NodeList>

截圖:

one-child

<NodeList>
    <span>I'm a NodeList Component's child.</span>
    <span>I'm a NodeList Component's child.</span>
</NodeList>

截圖:

more-than-one-child

[React]提供了一個工具方法React.Children來幫助處理【this.props.children】,使用React.children.map可以不需要理會組件下到底是有幾個節點,從而避免意外的錯誤產生。

PropTypes

【PropTypes】提供了一種驗證機制,來提醒用戶使用組件時應該要傳一些什麼值,如果傳的值不符合規範,只會得到一個warnning的提示,不會報錯。例如:

更多的類型校驗請參考官網:https://facebook.github.io/react/docs/typechecking-with-proptypes.html

/**
 * 調用方式
 * <PropsTypesExample name="ryn" age="12" />
 */

import React from 'react';

export default React.createClass({

    propTypes : {
        name : React.PropTypes.string.isRequired,
        age : React.PropTypes.number.isRequired
    },

    render() {
        return (
            <div className="App">
                My name is {this.props.name}, {this.props.age} year's old!
            </div>
        );
    }
});

會得到一個警告,如下:

prop-types

另外,還有一個getDefaultProps鉤子函數,用來設置組件的默認【props】,注意,這個鉤子方法當多次被調用的時候,只會被執行一次。例如:

/**
 * 調用方式
 * <DefaultPropsExample />
 */

import React from 'react';

export default React.createClass({

    getDefaultProps() {

        console.log("default execute!");

        return {
            name : 'Ryn',
            age : 12
        }
    },

    render() {
        return (
            <div className="App">
                My name is {this.props.name}, {this.props.age} year's old!
            </div>
        );
    }
});

// 當我連續兩次調用時,例如:
ReactDOM.render(
    <div>
        <DefaultPropsExample />
        <DefaultPropsExample />
    </div>,
    document.getElementById("root")
);

// 控制檯只會出現一次打印結果,如下

execute-once

refs(獲取真實的DOM元素)

可以使用[this.refs.xxx]來獲取真實的DOM節點,或者使用ReactDOM.findDOMNode(this.refs.xxx),例如:

/**
 * 調用方式
 * <RefsExample />
 */

import React from 'react';

export default React.createClass({

    handleClick() {
        let dom = this.refs.introduce;
        // or ReactDOM.findDOMNode(this.refs.introduce)
        console.log("dom", dom);
    },

    render() {
        return (
            <div className="App">
                <div ref="introduce" onClick={this.handleClick}>
                    <span>My name is Ryn, and I say hello!</span>
                </div>

            </div>
        );
    }
});

DOM節點打印如下:

refs

event

觸發事件,在refs中已經涉及到了DOM元素的click事件,更多的事件可以參看官網:https://facebook.github.io/react/docs/events.html,這裏主要講一下事件中的傳參問題。

React中的事件傳參,如果沒有傳參,只需要這樣調用:

<p className="hello" onClick={this.handleClick}>hello world!</p>

如果需要傳參,則需要綁定this,如果沒有綁定,則會變成直接調用函數了。例如:

<p className="hello" onClick={this.handleClick.bind(this, 1)}>hello world!</p>

接收函數,沒有傳參時,默認第一個參數是event事件對象,如果傳參,則最後一個參數是事件對象,例如:

/**
 * 調用方式
 * <EventExample />
 */

import React from 'react';

export default React.createClass({

    handleClick(num, e) {
        e.preventDefault();
        console.log("clicked", num);
    },

    render() {
        return (
            <div className="App">
                <div onClick={this.handleClick.bind(this, 1)}>
                    <span>My name is Ryn, and I say hello!</span>
                </div>
            </div>
        );
    }
});

state(組件的狀態)

state表示組件的狀態,當一個狀態發生變化時,會重新觸發render函數。注意,請將stateprops區分開,比較好的理解就是,props只是表示組件的屬性,不是可變的,但是一個組件的狀態是可以變化的,這時候就要用到state。例如如下的例子,會在每一秒改變元素的顏色:

/**
 * 調用方式
 * <StateExample />
 */

import React from 'react';

export default React.createClass({

    getInitialState() {
        return {
            isRed : true
        }
    },

    componentDidMount() {
        this.inter = window.setInterval(() => {
            this.setState({isRed : !this.state.isRed});
        }, 1000);
    },

    componentWillUnmount() {
        window.clearInterval(this.inter);
    },

    render() {

        let isRed = this.state.isRed, styles;

        styles = isRed ? {
            width : '100px',
            height : '100px',
            backgroundColor : 'red'
        } : {
            width : '100px',
            height : '100px',
            backgroundColor : 'blue'
        };

        return (
            <div className="App">
                <div style={styles}></div>
            </div>
        );
    }
});

表單

React中的表單分爲受限組件與不受限組件,受限組件受到組件本身控制,需要由state來維護,不可隨意更改,而不受限組件是由DOM本身控制,可以修改。React官方建議是採用受限組件來進行表單提交。詳情可以看這裏:

https://facebook.github.io/react/docs/forms.html

https://facebook.github.io/react/docs/uncontrolled-components.html

下面是一個例子:

/**
 * 調用方式
 * <FormExample />
 */

import React from 'react';

export default React.createClass({

    getInitialState() {
        return {
            name : 'ryn',
            age : 12
        }
    },

    changeInput(event) {
        this.setState({name : event.target.value});
    },

    changeSelect(event) {
        this.setState({age : event.target.value});
    },

    render() {
        return (
            <div className="App">
                <div>
                    <label htmlFor="name">name:</label>
                    <input type="text" name="name" value={this.state.name} onChange={this.changeInput} />
                </div>
                <div>
                    <label htmlFor="age">age:</label>
                    <select value={this.state.age} onChange={this.changeSelect}>
                        <option value="11">11</option>
                        <option value="12">12</option>
                        <option value="13">13</option>
                        <option value="14">14</option>
                        <option value="15">15</option>
                    </select>
                </div>
            </div>
        );
    }
});

react生命週期

react生命週期主要包括三個階段:初始化階段、運行中階段、銷燬階段

react在不同的生命週期會觸發不同的鉤子函數

想了解更多請參看官網:https://facebook.github.io/react/docs/react-component.html

初始化階段

getDefaultProps() 設置組件默認的屬性, 注意這個鉤子函數只會在組件第一次實例化的時候被調用,多次實例化的組件會共享同一份props

getInitialState() 組件的初始化狀態,可以通過用戶的操作來更改組件自身的狀態

componentWillMount() 在組件即將被渲染到頁面(組件還沒有真正渲染)

render() 組件渲染

componentDidMount() 組件被渲染到頁面上,在該方法中可通過this.getDOMNode()訪問到真實的DOM元素。此時已可以使用其他類庫來操作這個DOM

運行中階段

componentWillReceiveProps() 組件接收到屬性的時候調用,當組件的屬性發生變化的時候,並將其作爲參數nextProps使用,此時可以更改組件propsstate

componentWillReceiveProps: function(nextProps) {
    if (nextProps.bool) {
        this.setState({
            bool: true
        });
    }
}

shouldComponentUpdate() 當組件接收到新的屬性或者新的狀態發生變化的時候執行(在某些情況下當屬性或者狀態不發生變化的時候可以手動return false)

組件是否應當渲染新的propsstate,返回false表示跳過後續的生命週期方法,通常不需要使用以避免出現bug。在出現應用的瓶頸時,可通過該方法進行適當的優化

componentWillUpdate() 組件即將要被更新的時候調用(接收到新的props或者state後,進行渲染之前調用,此時不允許更新props或state)

render() 組件渲染

componentDidUpdate() 組件被更新完成之後調用,此時可以訪問到新的DOM元素

銷燬階段

componentWillUnmount() 組件被銷燬的時候被調用,給開發者最後的機會進行一些清理操作,比如對定時器的操作等等…

DOM元素

In React, all DOM properties and attributes (including event handlers) should be camelCased. For example, the HTML attribute tabindex corresponds to the attribute tabIndex in React. The exception is aria-* and data-* attributes, which should be lowercased.

在React中,所有的屬性都必須採用駝峯式寫法。例外就是aria-*data-*之類的,必須採用小寫。

幾個常用的不同點:

  • class -> className
<p className="title">hello</p>
// but not
<p class="title">hello</p>
  • for -> htmlFor
<label htmlFor="name">name:</label>
// but not
<label for="name">name:</label>
  • style
<div style={{padding:'10px',margin:'10px'}}></div>
// but not
<div style="padding:10px;margin:10px;"></div>

更多的不同點可以自己去官網瞭解 https://facebook.github.io/react/docs/dom-elements.html

參考鏈接

https://facebook.github.io/react/docs/hello-world.html

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

http://wiki.jikexueyuan.com/project/react/

https://github.com/Rynxiao/react-starter

發佈了60 篇原創文章 · 獲贊 29 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章