最新版React入門

工欲善其事必先利其器, 由於react崇尚的是, react一體化. 即, 使用js拯救世界. 因此, 咱們須要先將支持react的webpack 工具解決.html

webpack 配置

這裏主要使用的是這些模塊:node

"babel-loader": "^6.2.4",
        "babel-core": "^6.8.0",
        "babel-loader": "^6.2.4",
        "babel-plugin-transform-es2015-arrow-functions": "^6.8.0",
        "babel-preset-es2015": "^6.6.0",
        "react-dom": "^15.2.1",
        "react" : "^15.2.1"

將這些文件放到package.json中,而後使用npm install 便可.
這裏就不贅述了. 先放一個最簡單的webpack.config.js文件.react

var path = require('path'),
    node_modules = path.resolve(__dirname, 'node_modules');

module.exports = {
    // context: __dirname + "/app/src/entry",
    entry: {
       app:"./dev/app"
    }, //演示單入口文件
    output: {
        path: path.join(__dirname, '/dev/dist'), //打包輸出的路徑
        filename: '[name].entry.js', //打包後的名字
    },
    module: {
        loaders: [{
                test: /\.js|\.jsx$/,
                exclude: /(node_modules|bower_components)/,
                loader: 'babel?presets[]=es2015' //加載使用loader
            }
        ]
    },
    plugins: [
    ],
    watch: true
};

這裏須要注意一下, 因爲版本的問題, webpack 在v1.13以後, 會默認給entry文件添加extensions. 因此若是你的entry寫成了,./dev/app.js的話, 恭喜你, 踩坑了. 若是萬一出錯了, 你可使用webpack

webpack --display-error-details

來進行排查. ok , 如今咱們正式進入react時間web

react 入門

初期, react基本的操做無外乎就是圍繞着,Component和ReactDOM進行編寫和渲染。 之前, react並無分的太細化, 不過在version 0.14版本後, ReactDOM和Component就分開了, 主要仍是由於React Native的原因.
不過, 二者分開事後,形成的影響來講, 仍是不小的. 主要影響到三個方面:算法

  • ReactDOM.render(): 渲染UI層npm

  • ReactDOM.findDOMNode(): 獲取節點json

  • ReactDOM.renderToString(): 後端運用的轉義String方法後端

上面, 咱們已經下載好了reactreact-dom. 咱們能夠來簡單看一個demo:安全

import React,{Component} from 'react';
import ReactDOM from 'react-dom';

class Hello extends Component{
    render(){
        return (
        <h1>Hello world</h1>
            );
    }
}
ReactDOM.render(<Hello />,document.getElementById('container'));

重要的是Hello 類中的render方法. 經過return, 返回虛擬的DOM, 而後通過ReactDOM將虛擬的DOM, 渲染到指定節點內部.

動態內容

假如咱們如今想要在render中, 使用變量,so how to do?
很簡單, 只要在DOM裏面用到curly braces({})便可.

class Hello extends Component{
    render(){
        let name="jimmy";
        return (
        <h1>Hello {name}</h1>
            );
    }
}

嵌套UI

React之因此這麼流行,就是由於他的可複用性. 經過< classname /> 這樣的調用, 就能夠完美的實現, 組件的複用

class UI_item extends Component{
    render(){
        return (
                <UL></UL>
            );
    }
}
class UL extends Component{
    render(){
        return (
            <ul>
                <Li_item name="jimmy">ok</Li_item>
                <Li_item name="sam">yes</Li_item>
            </ul>
            )
    }
}

class Li_item extends Component{
    render(){
        return (
        <li>my name is {this.props.name} &nbsp; and my content is {this.props.children}</li>
            )
    }
}

在進行組件複用時, 重用UI 和寫HTML同樣, 使用閉合標籤,添加屬性等等. 不過,這裏須要注意一下, 在JSX語法中, class屬性須要換成 className(由於內部衝突).
另外, 說起一下上文出席那的兩個內容. this.props.xx 和this.props.children

  • this.props.xxx : 是用來得到節點中的屬性內容. 好比: name, data-name,data-set等等.

  • this.props.children: 用來獲取閉合tag中的內容. 好比: < div>abc< /div> 獲取獲得爲: abc

this.props 在組件複用中,是佔很重要的地位的, 能夠說,他是parent和children 組件通訊的重要通道, 父組件 賦值, 子組件處理. like:

UI

一般來講, 寫一個總體的UI 有兩種方式, 一種是Top-Down, 一種是Bottom-Up. 二者都行, 只是思考的方式不同, 不過通常TD(自頂向下)方式比較廣泛些.

若是你想利用循環生成jsx的話, 可使用:

class UL extends Component{
    render(){
        let tasks = [];
        for(var i=1,len=this.props.number;i<=len;i++){
            tasks.push(
                <Li_item key={i} number={i}>list</Li_item>
                )
        }
        return (
            <ul>
                {tasks}
            </ul>
            );
    }
}

但須要注意的是, 你不能直接寫爲:

return (
    {tasks}
)

若是這樣寫的話,react是不會讓你經過的. 由於他認爲你這個是不合法數據, 通常來講, 不能在第一層裏面直接寫入: arrar,object 對象.

狀態改變

react 提供另一個狀態屬性-this.state. React 經過改變父組件自己的state, 會致使DOM的從新渲染, 至關於從新調用ReactDOM.render().

have a try

這裏, 咱們經過簡單的改變, 父組件的state, 來實現節點的重流和重繪.
實現的demo 放在jsFiddler上, 能夠參考一下. 這裏我只貼精華的demo:

class UI_item extends Component{
    constructor(){
        super();
        this.state={
            origin:true
        }
    }
    render(){
        let number = 5;
        if(!this.state.origin){
            number*=2;
        }
        return (
                <div>
                    <button onClick={()=>{this.doubleNumber()}}></button>
                    <UL number={number}></UL>
                </div>
            );
    }
    doubleNumber(){
        this.setState({
            origin:!this.state.origin
        });
    }
}

上面的代碼其實有點繞的. 這裏補充幾點, 相信看過以後,再回去看代碼也就明白了.

  • this.setState({xxx:xxx}): 該方法是父組件的專屬方法, 其能夠手動的修改state的狀態, 來實現狀態的更新.

  • this.state: 初始狀況下,是在constructor 方法中, 直接設置。 不過, 你也能夠放在render 方法中, 這也是沒問題的.

  • 事件綁定: React中綁定事件的代碼雖然有點奇葩, 但他確實是綁定事件最簡潔的辦法. 他會在後面的流程中,自動解析事件內容, 而後使用addEventListener進行綁定.

另外, 你新增this.props也是會從新渲染節點的.

結合,上面的this.props 能夠大概瞭解, React 提供的精華架構.

framework

事件綁定解析

React 之因此高性能, 不只在於虛擬DOM的算法, 事件綁定也在必定程度提高性能. 由於React的全部事件都是綁定在document 根元素上.
比較好的綁定方式是,經過函數+bind方法進行綁定的

render(){
        let number = 5;
        if(!this.state.origin){
            number*=2;
        }
        return (
                <div>
                    <button onClick={this.doubleNumber.bind(this)}}></button>
                    <UL number={number}></UL>
                </div>
            );
    }

來看一下,React 提供的事件.
from pro react

event

當心JSX的坑

React 在提出自己的同時, 也提出了JSX語法. 這是爲何呢?
咱們能夠看一下,React 是如何翻譯JSX語法, 你就應該知道爲何JSX很受歡迎~

// JSX
<h1>Hello World</h1>

// React 方法調用
React.createElement("h1", null, "Hello World");

當你寫出JSX 的時候,React在背後已經幫你解析成對應的方法了. 因此, 這樣隱形的API, 爲何不用呢?
不過JSX 中有部份內容須要注意一下.

駝峯命名的屬性

在JSX中, 給tag添加屬性時,須要使用駝峯命令. 即.

// HTML
<input type="text" name="usrname" maxlength="10">

// JSX
<input type="text" name="usrname" maxLength="10"><br>

但像,這樣的data-set 使用dash鏈接的就不須要額外的注意. 另外, react 特別強調了class須要寫爲className. 由於在React內容,class 存在衝突, 因此強制性將class property改成了className.

標籤閉合

很簡單, 就是全部標籤必須閉合. 好比像<img src="...">這樣的, 後面的/ 能夠寫可不寫. 可是, 如今在JSX中,全部的都必須寫.

<img src="..." />

only one node

這裏,應該是不少初入React 童鞋經常犯的~ 可能對函數的瞭解還未透徹. 好比一個函數:

function add(){
    return (1,2);
}
add();

上面的結果是多少?
很簡單是2. 這是解析引擎所決定的. 由於, 直接經過return 語句返回, 永遠只能返回一個值.因此, 這也決定了在React中, 你使用render返回JSX時, 只能帶上一個節點.

// 正確
return(
  <h1>Hello World</h1>
)

// go die
return (
   <h1>Hello World</h1>
    <h2>Have a nice day</h2>
 )

改寫一下, 你只能返回一個節點:

return (
    <p>
        <h1>Hello World</h1>
        <h2>Have a nice day</h2>
    </p>
 )

don't use if-else

在JSX, 通常不要亂用if-else. 由於if-else 是不會返回任何值的。

// 報錯
return (
            <li data-set={if(true){"ok"}}>jimmy</li>
        )

推薦狀況是, 使用三元運算(ternary). 由於他能夠返回值.

return (
            <li data-set={true?'ok':0}>jimmy</li>
        )

置於爲何, 咱們能夠在這裏剖析一下JSX語法的結構. 前文已經提到了, JSX其實就是React.createElement(). 咱們的屬性其實,就是當作createElment參數的

// JSX
<div className={if (condition) { "salutation" }}>Hello JSX</div>

// 翻譯
React.createElement("div", {className: if (condition) { "salutation"}}, "Hello JSX");

這裏, 有點基本常識的應該知道, 對象裏面怎麼執行... 除非你有返回值.

空格省略

React在渲染的時候,會默認忽略掉元素間的空格. 估計是考慮到了inline-block 形成的3~4px的影響.

<li >{this.props.children}_{this.props.number}
                <a href="">ok</a>
                <a href="">yes</a>
</li>

這樣渲染的結果是

omit space

不過, 若是你僅僅是填寫文本的話, 裏面的空格就不會被忽略。若是, 你想在元素之間添加上空格的話. 能夠這樣寫:

<li >
                <a href="">ok</a> {" "}
                <a href="">yes</a>
</li>

JSX的評論

在JSX中,寫評論的話, 須要注意他的註釋方式:

/* comment */

另外,若是你的註釋是childElement, 則須要使用{}括起來. 但在元素內部評論的話,就不須要了

<Nav>
    {/* this is a child comment */}
    <Person
/* multi line
         comment */
      name="sam" // end of line comment
/> </Nav>

上面的demo 基本上把全部註釋狀況都包含了.

動態插入HTML

之前,咱們純原始寫組件的時候, 經常利用的就是element的innerHTML屬性. 即, 直接在html tag裏面添加string, 而後利用內部渲染,將element渲染出來.

<li>
    {this.dynamicP()}
</li>
// 動態腳本

dynamicP(){
        let p = "<p>123</p>";
        return p;
    }

可是, 這樣容易犯的一個錯誤就是XSS, 由於XSS最經常使用的手段就是動態惡意腳本的插入. 有興趣的童鞋,能夠參考一下個人xss之網頁安全.
React考慮到這點, 果斷將全部一切插入的String進行轉義.
因此, 上面渲染出來的會是這樣的:

p

當有時候,咱們又不得不使用動態的String當作HTML插入, 那應該怎麼作呢?
官方給出的解決辦法是, 使用dangerouslySetInnerHTML這個屬性.

<span dangerouslySetInnerHTML={{__html:dynamicP()}} />

這樣, React就會對插入的HTML解除XSS的限制.

表單輸入

爲何說表單輸入在React裏面也是一塊須要注意的呢?
由於, 一旦你設置在input的value屬性. 後面你全部的輸入都是無效的.

<input type="search" value="React" />

so how to solve it?
這裏就須要使用onChange和this.state來幫助咱們進行重繪.

class Search extends Component {
    constructor(){
        super();
        this.state={
            value:"React"
        }
    }
    render() {
        return ( <div>
        Search Term: <input type="search" value={this.state.value} onChange={this.handleChange.bind(this)} /> </div>
        )
    }
    handleChange(event){
        this.setState({
            value:event.target.value
        })
    }
}

經過輸入,觸發onChange, 而後onChange 觸發this.setState, 從新渲染DOM。get~ 線上demo

另外,表單輸入,還須要注意另外兩個ele. textarea和select.

textArea 在React中, textarea的書寫格式和HTML中有些不一樣

// HTML
<textarea>This is the description.</textarea>

// React
<textarea value="This is a description." />

該element 也須要綁定onChange時間才行.

select 元素的寫法和原始HTML差異不大,只是裏面的選取默認的option須要改變一下。 在HTML中, 書寫默認的option 只須要添加selected屬性便可. 但在React, 則須要手動指定value才行.

<select value="B">
    <option value="A">A</option>
    <option value="B">B</option>
    <option value="C">C</option>
</select>

反模式表單

這裏所謂的anti-pattern(反模式) 聽起來逼格挺高的. in fact, 他仍是表單. 只是你不用寫value屬性. 而這裏的反模式實際體如今, 你不用綁定onChange事件, 元素中的內容,也能隨着用戶的輸入自動變化.
看個demo:

render() {
        return (
            <form>
                    {/*
                    controled component
                     */}
                <input    type="text" value="fixed" /><br/>
                    {/*
                    uncontroled component
                     */}
                <input type="text" />
            </form>
        );

線上demo請參考: JSfiddle
那 uncontroled component 和 controled component 之間的區別是神馬嘞?
簡而言之, 若是你的表單須要有不少限制那麼就用controled component, 若是沒有能夠考慮uncontroled.

咱們總結一下:

JSX

內部屬性trick

key的使用

React 以他Virtual DOM 而聞名遐邇, 經過造出一個Virtual DOM, 而後, 經過一種比較算法,得出最新的DOM結構, 從而讓頁面性能損耗降到最低. 如今咱們考慮一種狀況.
即, 渲染重複的list.即:

return (
            <ul>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
            </ul>
        );

當其中的幾個節點須要變爲:

<ul>
                <li></li>
                <li></li>
                <li>1</li>
                <li></li>
                <li>2</li>
                <li></li>
            </ul>

React會怎麼作... 他首先會提示你, 孩紙, 你這樣不行... 由於, 這樣的實現方法是在是太多了. CRUD 哪種均可以實現上述行爲. 因此,React須要你手動的設置一個key值,來幫助他標識, 你改動的list是哪個~
上面的render咱們就須要改成:

render() {
        let lis = [];
        for(var i=0;i<4;i++){
            lis.push((
            <li key={i} >{i}</li>
            ))
        }
        return (
            <ul>
                {lis}
            </ul>
        );
    }

謹慎的refs

refs 其實是一種,黑魔法,又能夠稱爲語法糖. 由於他不須要咱們手動的使用document.getElementxxx 來獲取節點. 他已經幫你把dirty work 給幹好了. 咱們只須要使用this.refs.xx 來獲取指定節點便可. 可是, 官方是不提倡這種作法的,由於這樣破壞了數據的流向性. React原本是用過render, 來改變元素的狀態, 可是, 若是從外面使用this.refs 改變 DOM的話, 有可能會形成virtual DOM和actual DOM不統一的狀況.
若是你真的想用的話, 那就須要使用ref了, 這樣至少可能保證DOM狀態的統一. 能夠說, 在React中,你基本上能夠和document.xxx系列說拜拜了.

constructor(){
        super();
        this.number = 0;
    }
    render() {
        return(
            <div>
                <button onClick={this.clickButton.bind(this)}>click me</button>
                <span ref="text">I will be changed</span>
            </div>
            )
    }
    clickButton(){
        let text = this.refs.text;
        text.innerHTML = this.number++;
    }

注意一下, 屬性書寫是用ref, 獲取是使用refs. 線上demo, 參考:JSfiddle

相關文章
相關標籤/搜索