React基礎與項目搭建

網絡圖片

React簡介

React在2013年5月開源。
React可能是將來web開發的主流工具。
React不是一個完整的MVC框架,頂多充當一個View層。

  • MVC(Model+View+Controller)

不適用于前端開發,因為View不允許知道用戶的輸入,用戶的輸入是從Controller這一層進入。然而用戶直接通過view層交互,所以不可能不監聽View層。
MVVM(Model+View+ViewModel)——MVC的演變,更適合前端的開發模式。

  • JSX 解析器

將JSX轉化成JS,在JS中直接編寫HTML。
通過組建的state來維護改變HTML DOM中的內容。
所有和Dom有關的都應該通過框架來維護,
將各功能做成組建——模板(容器)、控件。

  • React組件及數據傳遞

React是一個組件化的框架,在項目開發之初需要將組件分化


搭建React Start Kit

1. 新建項目文件夾

這里取名newReactproject。
在該目錄下打開終端,初始化package.json

npm init

(可以輸入項目的名稱,這里為new-react-project)

2. 安裝插件

npm install --dev-save browser-sync gulp gulp-webpack jsx-loader react react-dom

3. JSX轉換成JS的方法

在gulpfile.js中用webpack來將.jsx文件轉化為.js文件
(gulp的使用在其他的章節里面會詳細說明)

var webpackConfig = {
    output:{
        filename: 'index.js'
    },
    devtool: 'inline-source-map',
    module:{
        loaders:[
            {test: /\.jsx$/, loader: 'jsx-loader'}
        ]
    },
    resolve:{
        extensions:['','.js','.jsx']
    }
}

gulp.task('script',function(){
    gulp.src('./jsx/index.jsx') //以index.jsx為程序的入口
        .pipe(webpack(webpackConfig))
        .pipe(gulp.dest('./www/script/'))
        .pipe(browserSync.stream());//同步瀏覽器
})

如此一來,就可以在.jsx文件中撰寫開發代碼了。

同時,需要注意的是:index.jsx中需要引用react

var React = require('react');
var ReactDom = require('react-dom')

如果需要在index.jsx中引用的組件,例如header,footer等,需要使用module.exports

module.exports = React.createClass({
    render:function(){
        return <p>這是一個React頁面</p>
    }
})

注意:實際項目中,node_modules文件會被刪除 ,那么運行項目的時候需要在終端輸入以下命令:

npm install gulp-cli -g
npm install
gulp

4. render語法

render一個變量時,要用html的方法來寫。
例如:

ReactDom.render(<Main />,document.getElementById('main'));

前面一個指render的內容,后一個變量是render的目的地

注意:ReactDom.render是新版本的寫法,舊版本是React.render()

//jsx語法中類名:
className="className";

//jsx語法中樣式:
style={{background:'#f00'}}
//jsx語法:
<tag prop={a:value}>{children}</tag>

//轉換成js是:
React.createElement(tag, {a:value}, children)

創建一個組件類,需要注意的幾點:

  • React中創建的組件類以大寫字母開頭,駝峰命名法
  • 在React中使用React.createClass方法創建一個組件類
  • 核心代碼:每個組件類都必須實現自己的render方法。輸出定義好的組件模板。返回值:null、false、組件模板
  • 注意:組件類只能包含一個頂層標簽

5. React Component

  • render:渲染html的方法
  • getInitialState: 返回初始化的State的方法
  • getDefaultProps:返回默認props的方法
    (state維護component內部的狀態變化,props是component的外部的參數傳入component的方式)
  • propTypes:定義props的類型的屬性
  • mixins:用來合并兩個組件的屬性
  • statics:定義靜態對象的屬性
  • displayName:定義該類在Debug信息中顯示的名稱

6. Props

Props是組件自身的屬性,一般用于嵌套的內外層組件中,負責傳遞信息(通常是由父層組件向子組件傳遞)

注意:props對象中的屬性與組件的屬性一一對應,不要直接去修改props中的屬性值。

//定義WebName
var WebName = React.createClass({
    render:function(){
        return <h1>{this.props.webname}</h1>;
    }
})

//定義WebLink
var WebLink = React.createClass({
    render:function(){
        return <a href={this.props.weblink}>{this.props.weblink}</a>;
    }
})

//定義WebShow
var WebShow = React.createClass({
    render:function(){
        return (
            <div>
                <WebName webname={this.props.wname} />
                <WebLink weblink={this.props.wlink} />
            </div>
        );
    }
})

//渲染
ReactDOM.render(
    <WebShow wname="網站名稱" wlink="http://www.baidu.com" />,
    document.getElementById("container")
)
  • ...this.props:

Props提供的語法糖,可以將父組件中的全部屬性都復制給子組件

例如:定義一個組件Link,Link組件中只包含一個<a>,我們不給<a>設置任何屬性,所有屬性全部從父組件膚質得到。代碼如下:

var Link = React.createClass({
    render:function(){
        return <a {...this.props}>{this.props.name}</a>
    }
});

ReactDOM.render(
    <Link  name="百度"/>,
    document.getElementById("container")
)
//這樣父組件上的屬性href和name都會被復制到子組件Link中的<a>上。
  • this.props.children:

children是一個例外,不是跟組件的屬性對應的。children表示組建的所有子節點

var ListComponent = React.createClass({
    render:function(){
        return (
            <ul>
                {
                    /*
                    列表項數量以及內容不確定,在創建模板時才能確定
                    利用this.props.children從父組件獲取需要展示的列表項內容
                    
                    獲取到列表項內容后,需要遍歷children逐行進行設置
                    使用React.Children.map方法
                    該方法的返回值:數組對象
                    */
                    React.Children.map(this.props.children, function(child){
                        //child是便利得到的父組件的子節點
                        return <li>{child}</li>
                    })
                }
            </ul>
        )
    }
});

//渲染
ReactDOM.render(
    (
        <ListComponent>
            <h1>百度</h1>
            <a >http://www.baidu.com</a>
        </ListComponent>
    ),
);

7. 屬性驗證 propTypes

組件類的屬性,用于驗證組建實例的屬性是否符合要求

var ShowTitle = React.createClass({
    propTypes: {
        //title數據類型必須為字符串
        title:React.PropTypes.string.isRequired
    },
    render:function(){
        return <h1>{this.props.title}</h1>
    }
});

ReactDOM.render(
    <ShowTitle title="123"  />,
    document.getElementById("container")
)
  • 設置組件屬性的默認值

通過實現組件的getDefaultProps方法,對屬性設置默認值。

var MyTitle = React.createClass({
    getDefaultProps: function(){
        return {
            title: "百度"
        };
    },
    render: function(){
        return <h1>{this.props.title}</h1>
    }
});

ReactDOM.render(
    <MyTitle />,
    document.getElementById("container")
);

8. state:

state和props一樣都是組件自身的屬性,都可以用來傳遞數據。
在和用戶交互的過程中,組件的狀態可能需要更新,就會觸發組件的重新渲染。

先舉個例子說明React事件的引用:

//定義一個button組件,綁定onClick事件

//React中的事件名稱首字母小寫,駝峰命名法

var MyButton = React.createClass({
    handleClick: function(){
        alert('點擊按鈕觸發的效果');
    },
    render: function(){
        return (
            <button onClick={this.handleClick}>{this.props.buttonTitle}</button>
        )
    }
});

ReactDOM.render(
    <MyButton buttonTitle="按鈕" />,
    document.getElementById("container")
);

在知道事件引用的方法后,再舉個經典案例:

需求:創建一個CheckButton的組件,包含一個checkbox類型的input,復選框在選中和未選中的兩種狀態下回顯示不同的文字,即根據狀態渲染。

var CheckButton = React.createClass({
    //定義初始狀態
    getInitialState: function(){
        return {
            //在這個對象中設置的屬性將會存儲在state中
            //默認狀態是:未選中
            isCheck: false
        }
    },
    //定義事件綁定的方法
    handleChange: function(){
        //修改狀態值,通過this.state讀取設置的狀態值
        this.setState({
            isCheck: !this.state.isCheck
        });
    },
    
    render:function(){
        //根據狀態值,設置顯示的文字
        //在JSX語法中,不能直接使用if..else函數,使用三目運算符
        var text = this.state.isCheck ? "已選中" : "未選中";
        
        return (
            <div>
                <input type="checkbox" onChange={this.handleChange} />
                {text}
            </div>
        );
    },
});

//渲染
ReactDOM.render(
    <CheckButton />,
    document.getElementById("container")
);

需要注意的時:當state發生變化時,會調用組件內部的render方法

  • 表單

舉例說明:

需求:定義一個組件,將用戶在輸入框內輸入的內容進行實時顯示
分析:組件與用戶交互過程中,存在狀態的變化,即輸入框的值。

var Input = React.createClass({
    getInitialState: function(){
        return (
            value: "請輸入"
        );
    },
    handleChange: function(event){
        //通過event.target.value讀取用戶輸入的值
        this.setState({
            value: event.target.value
        });
    },
    render: function(){
        var value = this.target.value;
        return (
            <div>
                <input type="text" value={value} onChange={this.handleChange} />
                <p>{value}</p>
            </div>
        )
    },
});

ReactDOM.render(
    <input />,
    document.getElementById("container")
);

9. React Component生命周期時間

組件的生命周期分為三個狀態

  1. Mounting: 組件掛載,已插入真實DOM

    相關接口:

    (1)componentWillMount - 組件將要掛載。
    在render之前執行,但僅執行一次,即使多次重復渲染該組件,或者改變了組件的state

    (2)componentDidMount - 組件已經掛載。
    在render之后執行,同一個組件重復渲染只執行一次

  2. Updating: 組件更新,正在被重新渲染

    相關接口:

    (1)componentWillReceiveProps(object nextProps)- 已加載組件收到新的props之前調用,注意組件初始化渲染時則不會執行

    (2)shouldComponentUpdate (object nextProps, object nextState) - 組件判斷是否重新渲染時調用。該接口實際是在組件收到了新的props或者新的state的時候會立即調用,然后通過下面兩個方法來進行更新

    (3)componentWillUpdate (object nextProps, object nextState) - 組件將要更新

    (4)componentDidUpdate (object prevProps, object prevState) - 組件已經更新

  3. Unmounting: 組件移出,已移出真實DOM

    相關接口:

    componentWillUnmount - 在組件要被移除之前的時間點觸發,可以利用該方法來執行一些必要的清理組件的工作

生命周期中與props和state相關的接口:

(1)getDefaultProps - 設置props屬性默認值

(2)getInitialState - 設置state屬性初始值

總結下來,一共九個接口,如下:

  • componentWillMount:組件的html即將加載時調用
  • componentDidMount:組件的html已經加載時調用
  • componentWillReceiveProps:組件props改變時調用
  • shouldComponentUpdate:判定組件是否更新HTML
  • componentWillUpdate:組件即將更新HTML時調用
  • componentDidUpdate:組件HTML更新完后調用
  • componentWillUnmount:組件HTML即將卸載時調用
  • getDefaultProps:設置props屬性默認值
  • getInitialState:設置state屬性初始值

組件的生命周期可分為四個階段創建實例化、更新、銷毀

生命周期個階段介紹

var Demo = React.createClass({
    /*
    一、創建階段
        流程:只調用getDefaultProps方法
    */
    getDefaultProps: function(){
        //在創建類的時候被調用,設置this.props的默認值
        console.log("getDefaultProps");
        return {};
    },
    
    /*
    二、實例化階段
        流程:
        getInitialState, 
        componentWillMount, 
        render, 
        componentDidMount
    */
    getInitialState: function(){
        //設置this.state的默認值
        console.log("getInitialState");
        return {};
    },
    componentWillMount: functon(){
        //在render之前調用
        console.log("componentWillMount");
    },
    render:function(){
        //渲染并返回一個虛擬DOM
        console.log("render");
        return <div>Hello React</div>
    },
    componentDidMount: function(){
        //在render之后調用
        //在該方法中,React會使用render方法返回的虛擬DOM對象創建真實的DOM結構
        //可以在這個方法中讀取DOM節點
        console.log("componentDidMount");
    },
    
    /*
    三、更新階段
        流程:
        componentWillReceiveProps, 
        shouldComponentUpdate (如果返回值是false,后三個方法不執行),
        componentWillUpdate, 
        render, 
        componentDidUpdate
    */
    componentWillReciveProps: function(){
        console.log("componentWillReciveProps")
    },
    shouldComponentUpdate: function(){
        //是否需要更新
        console.log("shouldComponentUpdate");
        return true;
    },
    componentWillUpdae: function(){
        console.log("componentWillUpdae");
    },
    componentDidUpdate: functon(){
        console.log("componentDidUpdate")
    },
    
    /*
    四、銷毀階段
        流程:componentWillUnmount
    */
    componentWillUnmount: function(){
        console.log("componentWillUnmount")
    },
});

//第一次創建并加載組件
//將得到以下順序:getDefaultProps,getInitialState,componentWillMount,render,componentDidMount
ReactDOM.render(
    <Demo />,
    document.getElementById("container")
);

//第二次創建并加載組件
//將在第一次加載的基礎上,添加以下順序:componentWillReceiveProps,shouldComponentUpdate,componentWillUpdate,render,componentDidUpdate
ReactDOM.render(
    <Demo />,
    document.getElementById("container")
);

//移除組件
ReactDOM.unmountComponentAtNode(document.getElementById("container"))

10. 設置組件的樣式

  • 內連樣式
  • 對象樣式
  • 選擇器樣式

注意:在ReactHTML5中,樣式的書寫方式是有所區別的

主要體現在:

  • HTML5以;結尾,React以,結尾
  • HTML5中key、value都不加引號,React中屬于JavaScript對象,key的名字不能出現“-”,需要使用駝峰命名法。如果value為字符串,需要加引號。
  • HTML5中,value如果是數字,需要帶單位,React中不需要帶單位。
//樣式
<style>
    .pStyle {
        font-size:20px;
    }
</style>

//創建設置h1樣式對象
var hStyle = {
    backgroundColor:"green",
    color:"red"
}

var ShowMessage = React.createClass({
    render:function(){
        return(
            //內連樣式
            <div style={{backgroundColor:"yellow",borderWidth:5,borderColor:"black",borderStyle:"solid"}}> 
                //對象樣式
                <h1 style={hStyle}>{this.props.firstRow}</h1>
                //選擇器樣式
                <p className="pStyle">{this.props.secondRow}</p>
            </div>
        )
    }
})

//渲染效果
ReactDOM.render(
    <ShowMessage firstRow="第一行" secondRow="第二行"/>,
    document.getElementById("container")
)

注意:在React中使用選擇器樣式設置組件樣式時,屬性名不能使用class,因為classReact中的保留字,需要使用className替換。
類似的還有使用htmlfor替換for,因為for也是React中的保留字。

11. 復合組件 —— 也稱為組合組件,父子組件(創建多個組件合成一個組件)

//定義WebName組件
var WebName = React.createClass({
    render:function(){
        return <h1>網站名稱</h1>;
    }
});

//定義WebLink組件
var WebLink = React.createClass({
    render:function(){
        return <a >http://www.baidu.com</a>;
    }
});

//定義WebShow復合組件
var WebShow = React.createClass({
    render:function(){
        return (
            <div>
                <WebName />
                <WebLink />
            </div>
        );
    }
    
});

//渲染
ReactDOM.render(
    <WebShow />,
    document.getElementById("container")
);

注:以上所有內容都是本人的學習筆記和總結,僅供學習和參考,如果有遺漏或者不當的地方請諒解,請勿轉載。

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

推薦閱讀更多精彩內容