前端(八):react入門

  React 特色:聲明式設計、虛擬DOM、JSX、組件、數據驅動。javascript

1、環境搭建

  1.安裝npm、cnpm

# 安裝node.js 從而安裝npm,它會在當前用戶家目錄下生成node_moudules文件夾,來對npm安裝的全局第三方包進行管理
brew install node
# npm安裝cnpm,由於npm默認的庫下載速度太慢,因此建議使用cnpm指定淘寶庫 npm
install -g cnpm --registry=https://registry.npm.taobao.org npm config set registry https://registry.npm.taobao.org # 測試 cnpm install express -g

  2.安裝react全家桶

# 安裝create-react-app
cnpm install create-react-app -g
# 利用create-react-app 來建立一個項目
create-react-app 項目名稱 # 假設這裏的項目名稱是my-app
# 進入項目文件夾
cd my-app
# 生成配置文件
# cnpm run eject # 生成scripts文件夾和config文件夾,cnpm
# 啓動服務
cnpm start # 它至關於執行 scrpits/starts.js,這個已經在package.json中配置好了

  3.文件目錄結構

my-app
    - config                        # 項目默認配置文件,由npm run eject生成
    - .gitignore                    # git配置
    - node_modules                  # 本地第三方安裝包
    - package.json                  # npm項目配置,裏面記錄了項目的名字、版本、依賴包、和自定義配置 
    - package-lock.json
    -  public                       # 公共資源
       - index.html                # 靜態頁面
    - README.md            
    -  scripts                      # 配置pacakage.json中的"scripts"定義的命令
        - build.js                  # build命令,可由npm build執行,生成靜態文件用於遷移到生產環境
        - start.js                  # start命令
        - test.js                
    -  src
        - App.css                   # 建立項目時自動生成的css樣式,沒用
        - App.js                    # react組件
        - App.test.js
        - index.css                 # 入口文件的樣式
        - index.js                  # 入口文件
        - log.svg
        - registerServiceWorker.js

  項目啓動時,會加載public下的index.html文件,並進而執行index.js,從而完成整個頁面的渲染。css

2、react一些概念

<!--public/index.html簡化以下-->
<!
DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="theme-color" content="#000000"> <title>React App</title> <style> body { margin: 0; padding: 0; } </style> </head> <body> <div id="root"></div> </body> </html>

  react簡單示例只保留簡化後的public/index.html和src/index.jshtml

  1.React.Component

  React.Component是自定義組件的父類,必須重寫render方法來完成組件的聲明和返回。所謂組件,就是用js類定義的一組html標籤、樣式、數據、事件等的整合,該類能夠用<類名 />的方式進行標籤化(實例化),實例化時自動調用render方法,並最終交由React.render完成渲染。java

  一張網頁就能夠分割成多個組件,每一個組件本身實現標籤、樣式、數據交互和用戶交互。也就是說,網頁是由多個組件堆砌而成的,每一個組件都必須繼承React.Component來實現並返回本身的定製化。顯然地,組件既包含一個div標籤組,自己也是一個類,它具備雙重角色。node

  一個繼承了React.Component的組件,經過render返回一個組件對象。經驗上談,一個子類的某個固定方法極有多是其父類方法(或接口)的重寫(實現),而每每這個方法會在程序運行時被自動調用。所以,render方法是重寫了React.Component,在程序啓動時被自動執行,掛載到網頁的某個節點上。react

import React, {Component, Fragment} from "react";

class Boom extends Component{
    render() {
        return (
            <Fragment>
                <div>
                    <input /><button>提交</button>
                </div>
                <ul>
                    <li>what the hell?</li>
                    <li>你瞅啥子</li>
                </ul>
            </Fragment>
        )
    }
}

export default Boom;

  2.ReactDOM.render

  index.js中的ReactDOM.render函數用於將標籤或者組件渲染到public下的頁面中。第一個參數能夠是任意的單個標籤、div包裹的多個標籤,以及自定義的組件Component。git

  ReactDOM.render用於將組件掛載到某個標籤上。好比html中某個id爲root的div標籤上。簡單粗暴:一個包含了西瓜瓤、西瓜籽、西瓜皮的西瓜掛在了西瓜藤上。express

  3.React JSX

  用於編譯jsx語法。React.Component和ReactDOM.render中的標籤都使用了jsx語法,因此必須使用React進行編譯。JSX看起來像是急於XML的javascript的擴展。它編寫簡單而且執行更快,同時也是類型安全的,在編譯過程當中就能發展錯誤。npm

  經驗之談:若是一個標籤的首字母時大寫,那麼它就遵循JSX語法,若是一個標籤的首字母小寫,那麼它就是原始html標籤(但這個標籤有多是按照jsx語法編譯的)。json

  JSX容許在一對{}中寫js代碼,例如:

{
     /*
          遍歷list生成li標籤,並給每一個li標籤添加刪除功能
     /
     this.state.list.map(
          (item, index) => {
                return <li
                            key={index}
                            onClick={(index)=>{this.handleLiDelete(index)}}
                       > { item }</li>
          }
) }

  4.組件內部參數聲明和使用

  組件內部能夠聲明參數,不管是textNode仍是其它Node,都是以 { 參數 } 的形式被組件調用。組件react虛擬DOM的具體實現方式,它來完成對頁面和業務邏輯的劃分。

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component{
render (){
const string = "hello, react!";
const style1 = {
color: "white"
};
const style2 = {
textAlign:"center",
fontStyle: "border",
backgroundColor: "green"
};
return (
<div style={style1}>
{/*這是一段註釋*/}
<h2 style={style2}>{ string }</h2>
</div>
)
}
}

ReactDOM.render(<div>
<h2>hello, react!</h2>
<App />
</div>, document.getElementById('root'));

  組件間能夠實現嵌套。

import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component{
render (){
return <h2>這是子組件</h2>
}
}
class App2 extends React.Component{
render (){
const style = {
backgroundColor: "blue"
};
return (
<div style={style}>
<h2>這是父組件</h2>
<App />
</div>
)
}
}

ReactDOM.render(<App2 />, document.getElementById('root'));

  5.靜態數據傳遞--props

  組件間數據經過this.props屬性來進行數據傳遞。父組件在標籤化時經過屬性的方式傳遞數據,子組件經過this.props來獲取全部的數據。

import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component{
render (){
return <h2>App: { this.props.name }, { this.props.age }</h2>
}
}
class App2 extends React.Component{
render (){
const name = "Sun", age=5000;

return (
<div>
<h2>App2: { this.props.name }, { this.props.age }</h2>
<App name={name} age={age} />
</div>
)
}
}
ReactDOM.render(<App2 name="Li" age="20" />, document.getElementById('root'));

  注意:1.props只能傳遞靜態數據,沒法與用戶交互;2.{}不是Object對象,若是想寫<App2 obj={name: "Li", age: 20} />,就必須提早聲明。3.style樣式做爲數據傳遞是無效且荒謬的。

const obj = {name: "Li",age: 20};
<App2 obj={obj}/>

  6.動態數據交互--state

  React是一個響應式框架,它將數據和dom分開,可以根據數據的變化自動更新dom。再次強調:React.Component具備雙重屬性:組件(dom)屬性和js類屬性(類:數據封裝)。

  state用於負責處理動態數據。數據須要在構造函數中經過this.state事先聲明,並在事件中經過this.setSate完成數據更新。

import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component{
constructor(props){
super(props);
this.state = {
nameList:["Sun", "Li", "Zhao", "Qian"]
}
}
addPerson(){
this.setState({
nameList: [...this.state.nameList, "zhou"]
})
}
render (){
return (
<div>
<button onClick={()=>this.addPerson()}>加入周先生</button>
<ul>
{this.state.nameList.map((name, index) => <li key={index+1}>{name}</li>)}
</ul>
</div>

)
}
}
ReactDOM.render(<App />, document.getElementById('root'));

  7.事件綁定

  在react中,事件以屬性的方式直接在標籤中使用,其調用函數要用一層函數包裹。調用函數能夠直接寫在對象內部,而且要用bind進行監聽和更新。

  在上面的示例中,咱們經過這一行代碼代替了bind的過程:

<button onClick={()=>this.addPerson()}>加入周先生</button>

  鑑於js中沒有局部做用域只有函數做用域,因此若是直接寫onClick={this.addPerson}時,this指的就是window對象。用一層函數包裹時,this對象指的就是這個函數。

  其它的作法有兩種:

  首先,在事件綁定時直接使用this.function:

<button onClick={this.addPerson}>加入周先生</button>

  其次能夠用箭頭函數來聲明addPerson函數,本質上和上面使用的方法同樣:

addPerson = ()=>{
this.setState({
nameList: [...this.state.nameList, "zhou"]
})
};

  或者能夠不改addPersonn函數,而是在構造器中添加上這麼一句話:

this.addPerson = this.addPerson.bind(this)

  一個示例:

import React, {Component, Fragment} from "react";

class Boom extends Component{
    constructor(props){
        super(props);
        this.state = {
            inputValue: "",
            list: []
        }
    }
    handleInputChange(e){
        this.setState({
            inputValue: e.target.value
        });
    }
    handleBtnClick(){
        this.setState({
            list:[...this.state.list, this.state.inputValue],
            inputValue: ""     // 在提交時自動清空輸入框裏的內容
        })
    }

    handleLiDelete(index){
        const list = [...this.state.list]; // 只能經過setState修改數據,因此不要寫成this.state.list.splice(index, 1);
        list.splice(index, 1);
        this.setState({
            list: list
        });
    }
    render() {
        return (
            <Fragment>
                <div>
                    <input
                        value={ this.state.inputValue }
                        onChange={this.handleInputChange.bind(this)}
                    />
                    <button onClick={()=>this.handleBtnClick()}>提交一個句子</button>
                </div>
                <ul>
                    {
                        this.state.list.map(
                            (item, index) => {
                                return <li
                                            key={index}
                                            onClick={(index)=>{this.handleLiDelete(index)}}
                                        > { item }</li>
                            }
                        )
                    }
                </ul>
            </Fragment>
        )
    }
}

export default Boom;

  8.條件渲染

  render自己是一個實例方法,支持js中的各類代碼邏輯。能夠用if-else來控制返回結果。條件渲染在用戶登陸和重定向中使用的比較頻繁。

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component{
constructor(props){
super(props);
this.state = {isLogIn: false}

}
login (){
this.setState({isLogIn: true})
};
logout(){
this.setState({isLogIn: false})
}
render (){
let button=null;
if (this.state.isLogIn){
button = <button onClick={()=>this.logout()}>註銷</button>
}else {
button = <button onClick={()=>this.login()}>登陸</button>
}
return button
}
}
ReactDOM.render(<App />, document.getElementById('root'));

  也能夠用三元表達式簡寫:

render (){
return (
<div>
{this.state.isLogIn ? <button onClick={()=>this.logout()}>註銷</button> : <button onClick={()=>this.login()}>登陸</button>}
</div>
)
}

  注意:因爲{}傳遞的數據能夠是任意值,因此須要用div包裹。

相關文章
相關標籤/搜索