React學習筆記知識點整理

1. 幾個重要概念理解

  • 模塊與組件css

    • 模塊:html

      • 理解: 向外提供特定(局部)功能的js程序, 通常就是一個js文件
      • 爲何: js代碼更多更復雜
      • 做用: 複用js, 簡化js的編寫, 提升js運行效率
    • 組件:node

      • 理解: 用來實現特定功能效果的代碼集合(html/css/js)
      • 爲何: 一個界面的功能更復雜
      • 做用: 複用編碼, 簡化項目編碼, 提升運行效率
  • 模塊化與組件化react

    • 模塊化:webpack

      • 當應用的js都以模塊來編寫的, 這個應用就是一個模塊化的應用
    • 組件化:ios

      • 當應用是以多組件的方式實現功能, 這上應用就是一個組件化的應用

2. React的基本認識

  • Facebook開源的一個js庫
  • 一個用來動態構建用戶界面的js庫
  • React的特色git

    • Declarative(聲明式編碼)
    • Component-Based(組件化編碼)
    • Learn Once, Write Anywhere(支持客戶端與服務器渲染)
    • 高效
    • 單向數據流
  • React高效的緣由程序員

    • 虛擬(virtual)DOM, 不老是直接操做DOM(批量更新, 減小更新的次數)
    • 高效的DOM Diff算法, 最小化頁面重繪(減少頁面更新的區域)

3. 使用React

* 導入相關js庫文件(react.js, react-dom.js, babel.min.js)
* 編碼:
    ```
  <div id="container"></div>
  <script type="text/babel">
    var aa = 123
    ReactDOM.render(<h1>{aa}</h1>, containerDOM);
  </script>
    ```

4. JSX

  • 全稱: JavaScript XML
  • react定義的一種相似於XML的JS擴展語法: XML+JSes6

    • 做用: 用來建立react虛擬DOM(元素)對象github

      • js中直接能夠套標籤, 但標籤要套js須要放在{}中
      • 在解析顯示js數組時, 會自動遍歷顯示
      • 把數據的數組轉換爲標籤的數組:

        var liArr = dataArr.map(function(item, index){
        return <li key={index}>{item}</li>
        })
  • 注意:

    • 標籤必須有結束
    • 標籤的class屬性必須改成className屬性
    • 標籤的style屬性值必須爲: {{color:'red', width:12}}

5. Component : React是面向組件編程的(組件化編碼開發)

* 基本理解和使用
    * 自定義的標籤: 組件類(函數)/標籤
    * 建立組件類
      ```
      //方式1: 無狀態函數(最簡潔, 推薦使用)
      function MyComponent1() {
        return <h1>自定義組件標題11111</h1>;
      }
      //方式2: ES6類語法(複雜組件, 推薦使用)
      class MyComponent3 extends React.Component {
        render () {
          return <h1>自定義組件標題33333</h1>;
        }
      }
      //方式3: ES5老語法(不推薦使用了)
      var MyComponent2 = React.createClass({
        render () {
          return <h1>自定義組件標題22222</h1>;
        }
      });
      ```
    * 渲染組件標籤
        ```
        ReactDOM.render(<MyComp />,  cotainerEle);
        ```
* ReactDOM.render()渲染組件標籤的基本流程
  * React內部會建立組件實例對象/調用組件函數, 獲得虛擬DOM對象
  * 將虛擬DOM並解析爲真實DOM
  * 插入到指定的頁面元素內部
* props
    * 全部組件標籤的屬性的集合對象
    * 給標籤指定屬性, 保存外部數據(多是一個function)
    * 在組件內部讀取屬性: this.props.propertyName
    * 做用: 從目標組件外部向組件內部傳遞數據
    * 對props中的屬性值進行類型限制和必要性限制
     ```
     Person.propTypes = {
       name: React.PropTypes.string.isRequired,
       age: React.PropTypes.number.isRequired
     }
     ```
* 擴展屬性: 將對象的全部屬性經過props傳遞
    ```
    <Person {...person}/>
    ```
* 組件的組合
    * 組件標籤中包含子組件標籤
    * 拆分組件: 拆分界面, 抽取組件
    * 經過props傳遞數據
* refs
    * 組件內包含ref屬性的標籤元素的集合對象
    * 給操做目標標籤指定ref屬性, 打一個標識
    * 在組件內部得到標籤對象: this.refs.refName(只是獲得了標籤元素對象)
    * 做用: 操做組件內部的真實標籤dom元素對象
* 事件處理
    * 給標籤添加屬性: onXxx={this.eventHandler}
    * 在組件中添加事件處理方法
      ```
        eventHandler(event) {
                    
        }
      ```
    * 使自定義方法中的this爲組件對象
      * 在constructor()中bind(this)
      * 使用箭頭函數定義方法(ES6模塊化編碼時才能使用)
* state
    * 組件被稱爲"狀態機", 頁面的顯示是根據組件的state屬性的數據來顯示
    * 初始化指定:
        ```
        constructor() {
          super();
          this.state = {
            stateName1 : stateValue1,
            stateName2 : stateValue2
          };
        }
        ```
    * 讀取顯示: 
        this.state.stateName1
    * 更新狀態-->更新界面 : 
        this.setState({stateName1 : newValue})
* 實現一個雙向綁定的組件
    * React是單向數據流
    * 須要經過onChange監聽手動實現
* 組件生命週期
    * 組件的三個生命週期狀態:
    * Mount:插入真實 DOM
    * Update:被從新渲染
    * Unmount:被移出真實 DOM
* 生命週期流程:
  * 第一次初始化顯示
    ```
    constructor()
    componentWillMount() : 將要插入回調
    render() : 用於插入虛擬DOM回調
    componentDidMount() : 已經插入回調
    ```
  * 每次更新state
    ```
    componentWillReceiveProps(): 接收父組件新的屬性
    componentWillUpdate() : 將要更新回調
    render() : 更新(從新渲染)
    componentDidUpdate() : 已經更新回調
    ```
  * 刪除組件
    ```
    ReactDOM.unmountComponentAtNode(document.getElementById('example')) : 移除組件
    componentWillUnmount() : 組件將要被移除回調
    ```
* 經常使用的方法
  ```
  render(): 必須重寫, 返回一個自定義的虛擬DOM
  constructor(): 初始化狀態, 綁定this(能夠箭頭函數代替)
  componentDidMount() : 只執行一次, 已經在dom樹中, 適合啓動/設置一些監聽
  ```

6. ajax

* React沒有ajax模塊
* 集成其它的js庫(如axios/fetch/jQuery/), 發送ajax請求
  * axios
    * 封裝XmlHttpRequest對象的ajax
    * promise
    * 能夠用在瀏覽器端和服務器
  * fetch
    * 再也不使用XmlHttpRequest對象提交ajax請求
    * fetch就是用來提交ajax請求的函數, 只是新的瀏覽才內置了fetch
    * 爲了兼容低版本的瀏覽器, 能夠引入fetch.js
* 在哪一個方法去發送ajax請求
  * 只顯示一次(請求一次): componentDidMount()
  * 顯示屢次(請求屢次): componentWillReceiveProps()

7. 虛擬DOM

  • 虛擬DOM是什麼?

    • 一個虛擬DOM(元素)是一個通常的js對象, 準確的說是一個對象樹(倒立的)
    • 虛擬DOM保存了真實DOM的層次關係和一些基本屬性,與真實DOM一一對應
    • 若是隻是更新虛擬DOM, 頁面是不會重繪的
  • Virtual DOM 算法的基本步驟

    • 用 JavaScript 對象結構表示 DOM 樹的結構;而後用這個樹構建一個真正的 DOM 樹,插到文檔當中
    • 當狀態變動的時候,從新構造一棵新的對象樹。而後用新的樹和舊的樹進行比較,記錄兩棵樹差別
    • 把2所記錄的差別應用到步驟1所構建的真正的DOM樹上,視圖就更新了
  • 進一步理解

    • Virtual DOM 本質上就是在 JS 和 DOM 之間作了一個緩存。
    • 能夠類比 CPU 和硬盤,既然硬盤這麼慢,咱們就在它們之間加個緩存:既然 DOM 這麼慢,咱們就在它們 JS 和 DOM 之間加個緩存。CPU(JS)只操做內存(Virtual DOM),最後的時候再把變動寫入硬盤(DOM)。

8. 使用React腳手架建立一個React應用

  • react腳手架

    • xxx腳手架: 用來幫助程序員快速建立一個基於xxx庫的空項目的庫

      • 包含了全部須要的配置
      • 指定好了全部的依賴
      • 能夠直接安裝/編譯/運行一個簡單效果
    • react提供了一個專門用於建立react項目的腳手架庫: create-react-app
    • 項目的總體技術架構爲: react + webpack + es6 + eslint
  • 建立項目並啓動

    • npm install -g create-react-app
    • create-react-app hello-react
    • cd hello-react
    • npm start

9. app1: 實現一個評論管理功能

  • 拆分組件:

    • 應用組件: App
    • 添加評論組件: CommentAdd
    • 評論項組件: CommentItem
    • 評論列表組件: CommentList
  • 肯定組件的state和props:

    • App:

      • state: comments/array
    • CommentAdd

      • state: username/string, content/string
      • props: add/func
    • commentList

      • props: comments/array, delete/func
    • CommentItem

      • props: comment/object, delete/func, index/number
  • 編寫靜態組件

    • 拆分頁面
    • 拆分css
  • 實現動態組件

    • 動態展現初始化數據

      • 初始化狀態數據
      • 傳遞屬性數據
    • 響應用戶操做, 更新組件界面

      • 綁定事件監聽, 並處理
      • 更新state

10. app2: 實現github用戶搜索功能

  • 拆分組件

    • App
    • Search
    • List
  • 肯定組件的state和props

    • App

      • state: searchName/string
    • Search

      • props: setSearchName/func
    • List

      • props: searchName/string
      • state: firstView/bool, loading/bool, users/array, errMsg/string
  • 編寫靜態組件
  • 編寫動態組件

    • componentWillReceiveProps(nextProps): 監視接收到新的props, 發送ajax
    • 使用axios庫發送ajax請求

11. 組件間通訊總結

  • 方式一: 經過props傳遞

    • 共同的數據放在父組件上, 特有的數據放在本身組件內部(state)
    • 經過props能夠傳遞通常數據和函數數據, 只能一層一層傳遞
    • 通常數據-->父組件傳遞數據給子組件-->子組件讀取數據
    • 函數數據-->子組件傳遞數據給父組件-->子組件調用函數
  • 方式二: 使用消息訂閱(subscribe)-發佈(publish)機制: 自定義事件機制

    • 工具庫: PubSubJS
    • 下載: npm install pubsub-js --save
    • 使用:

      import PubSub from 'pubsub-js' //引入
      PubSub.subscribe('delete', function(data){ }); //訂閱
      PubSub.publish('delete', data) //發佈消息

12. ES6新語法

  • const/let
  • 解構賦值: let {a, b} = this.props
  • 對象的簡潔表達
  • 箭頭函數:

    • 組件的自定義方法: xxx = () => {}
    • map/filter的回調方法: (item, index) => {}
    • 優勢:

      • 簡潔
      • 沒有本身的this,使用引用this查找的是外部this
  • 擴展運算符(...)

    • 解構對象: const MyProps = {}, <Xxx {...MyProps}>
  • class/extends/constructor/super
  • ES6模塊化(Babel)

13. 項目打包運行

  • 項目編譯打包並運行

    • npm build
    • npm install -g pushstate-server
    • pushstate-server build
    • 訪問: http://localhost:9000

14. 下載相關模塊包

  • 建立package.json
  • react相關庫

    npm install react react-dom --save
  • babel相關庫

    npm install babel-core babel-preset-es2015 babel-preset-react --save-dev
  • webpack相關庫

    npm install webpack babel-loader --save-dev
    npm install webpack-dev-server

15. webpack配置文件: webpack.config.js

const path = require('path'); //path內置的模塊,用來設置路徑。
        
module.exports = {
  entry: './src/main.js',   // 入口文件
  output: {                     // 輸出配置
    filename: 'bundle.js',      // 輸出文件名
    path: path.resolve(__dirname, 'dist')   //輸出文件路徑配置
  },
   module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            'style-loader',
            'css-loader'
          ]
        },
        //babel處理js
        {
          test: /\.js$/,
          exclude: /node_modules/, //排除此文件夾
          use: [
          'babel-loader'
          ]
        }
        
      ]
    }    
    
};

16. babel配置文件: .babelrc

{
  "presets": ["es2015", "react"]
}

17. 編碼

  • src/js/App.js: 應用組件

    import React from 'react'
    export default function App() {  //暴露組件都得使用默認暴露
      return <h1>Hello React Client Component</h1>
    }
  • src/js/main.js: 入口js

    import React from 'react'
    import ReactDOM from 'react-dom'
    import App from './App'
    
    //渲染組件標籤到頁面元素
    ReactDOM.render(<App />, document.getElementById('demo'))

18. 下載css加載器

npm install style-loader css-loader --save-dev

建立css文件  src/css/test.css

body{
    background : red
}

19. 配置webpack-dev-server

devServer:{
    contentBase: './',//內置服務器動態加載頁面所在的目錄
}
``
##20. 執行命令
構建任務:webpack
熱加載任務: webpack-dev-server
```

21 package.json: 添加編譯/運行腳本

"scripts": {
  "start": "webpack-dev-server",
  "build": "webpack"
}

react-router使用教程

0. 關於url中#的做用:

  • 學習: http://www.ruanyifeng.com/blo...
  • '#'表明網頁中的一個位置。其右面的字符,就是該位置的標識符
  • 改變#不觸發網頁重載
  • 改變#會改變瀏覽器的訪問歷史
  • window.location.hash讀取#值
  • window.onhashchange = func 監聽hash改變

1. reat-router

2. react-router庫中的相關組件

  • 包含的相關組件:

    • Router: 路由器組件, 用來包含各個路由組件
    • Route: 路由組件, 註冊路由
    • IndexRoute: 默認路由組件
    • hashHistory: 路由的切換由URL的hash變化決定,即URL的#部分發生變化
    • Link: 路由連接組件
  • Router: 路由器組件

    • 屬性: history={hashHistory} 用來監聽瀏覽器地址欄的變化, 並將URL解析成一個地址對象,供React Router匹配
    • 子組件: Route
  • Route: 路由組件

    • 屬性1: path="/xxx"
    • 屬性2: component={Xxx}
    • 根路由組件: path="/"的組件, 通常爲App
    • 子路由組件: 子<Route>配置的組件
  • IndexRoute: 默認路由

    • 當父路由被請求時, 默認就會請求此路由組件
  • hashHistory

    • 用於Router組件的history屬性
    • 做用: 爲地址url生成?_k=hash, 用於內部保存對應的state
  • Link: 路由連接

    • 屬性1: to="/xxx"
    • 屬性2: activeClassName="active"

3. 配置(從官方教程樣例中拷貝)

* webpack配置: webpack.config.js
    ```
    module.exports = {
      //入口js
      entry: './index.js',
      //編譯打包輸出
      output: {
        filename: 'bundle.js',
        publicPath: ''
      },
    
      module: {
        //使用的loaders
        loaders: [
          {test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader?presets[]=es2015&presets[]=react'}
        ]
      }
    }
    ```

  * 包配置: package.json
    ```
    {
      "name": "tutorial",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "start": "webpack-dev-server --inline --content-base ."
      },
      "author": "",
      "license": "ISC",
      "dependencies": {
        "react": "^0.14.7",
        "react-dom": "^0.14.7",
        "react-router": "^2.0.0"
      },
      "devDependencies": {
        "babel-core": "^6.5.1",
        "babel-loader": "^6.2.2",
        "babel-preset-es2015": "^6.5.0",
        "babel-preset-react": "^6.5.0",
        "http-server": "^0.8.5",
        "webpack": "^1.12.13",
        "webpack-dev-server": "^1.14.1"
      }
    }
    ```

4. 編碼

* 定義各個路由組件
    * About.js
      ```
      import React from 'react'
      function About() {
        return <div>About組件內容</div>
      }
      export default About
      ```
    * Home.js
      ```
      import React from 'react'
      function Home() {
        return <div>Home組件內容2</div>
      }
      export default Home
      ```
    * Repos.js
      ```
      import React, {Component} from 'react'
      export default class Repos extends Component {
        render() {
          return (
            <div>Repos組件</div>
          )
        }
      }
      ```
  * 定義應用組件: App.js
    ```
    import React, {Component} from 'react'
    import {Link} from 'react-router'
    
    export default class App extends Component {
      render() {
        return (
          <div>
            <h2>Hello, React Router!</h2>
            <ul>
              <li><Link to="/about" activeClassName="active">About2</Link></li>
              <li><Link to="/repos" activeClassName="active">Repos2</Link></li>
            </ul>
            {this.props.children}
          </div>
        )
      }
    }
    ```
  * 定義入口JS: index.js-->渲染組件
    ```
    import React from 'react'
    import {render} from 'react-dom'
    import {Router, Route, IndexRoute, hashHistory} from 'react-router'
    import App from './modules/App'
    import About from './modules/About'
    import Repos from './modules/Repos'
    import Home from './modules/Home'
    
    render((
      <Router history={hashHistory}>
        <Route path="/" component={App}>
          <IndexRoute component={Home}/>
          <Route path="/about" component={About}></Route>
          <Route path="/repos" component={Repos}></Route>
        </Route>
      </Router>
    ), document.getElementById('app'))
    ```
  * 主頁面: index.html
    ```
    <style>
      .active {
        color: red;
      }
    </style>
    <div id=app></div>
    <script src="bundle.js"></script>
    ```

5. 傳遞請求參數

* repo.js: repos組件下的分路由組件
    ```
    import React from 'react'
    export default function ({params}) {
      let {username, repoName} = params
      return (
        <div>用戶名:{username}, 倉庫名:{repoName}</div>
      )
    }
    ```
  * repos.js
    ```
    import React from 'react'
    import NavLink from './NavLink'
    
    export default class Repos extends React.Component {
    
      constructor(props) {
        super(props);
        this.state = {
          repos: [
            {username: 'faceback', repoName: 'react'},
            {username: 'faceback', repoName: 'react-router'},
            {username: 'Angular', repoName: 'angular'},
            {username: 'Angular', repoName: 'angular-cli'}
          ]
        };
        this.handleSubmit = this.handleSubmit.bind(this)
      }
    
      handleSubmit () {
    
        const repos = this.state.repos
        repos.push({
          username: this.refs.username.value,
          repoName: this.refs.repoName.value
        })
        this.setState({repos})
        this.refs.username.value = ''
        this.refs.repoName.value = ''
      }
    
      render() {
        return (
          <div>
            <h2>Repos</h2>
            <ul>
              {
                this.state.repos.map((repo, index) => {
                  const to = `/repos/${repo.username}/${repo.repoName}`
                  return (
                    <li key={index}>
                      <Link to={to} activeClassName='active'>{repo.repoName}</Link>
                    </li>
                  )
                })
              }
              <li>
                <form onSubmit={this.handleSubmit}>
                  <input type="text" placeholder="用戶名" ref='username'/> / {' '}
                  <input type="text" placeholder="倉庫名" ref='repoName'/>{' '}
                  <button type="submit">添加</button>
                </form>
              </li>
            </ul>
            {this.props.children}
          </div>
        );
      }
    }
    ```
  * index.js: 配置路由
    ```
    <Route path="/repos" component={Repos}>
      <Route path="/repos/:username/:repoName" component={Repo}/>
    </Route>
    ```
6. 優化Link組件
  * NavLink.js
    ```
    import React from 'react'
    import {Link} from 'react-router'
    export default function NavLink(props) {
      return <Link {...props} activeClassName="active"/>
    }
    ```
  * Repos.js
    ```
    <NavLink to={to}>{repo.repoName}</NavLink>
    ```

使用開源的ant-design庫開發項目指南

1. 最流行的開源React UI組件庫

2. ant-design使用入門

使用create-react-app搭建react開發環境

npm install create-react-app -g
create-react-app antd-demo
cd antd-demo
npm start

搭建antd的基本開發環境

  • 下載

    npm install antd --save
  • src/App.js

    import React, { Component } from 'react';
      import { Button } from 'antd';
      import './App.css';
      
      class App extends Component {
        render() {
          return (
            <div className="App">
              <Button type="primary">Button</Button>
            </div>
          );
        }
      }
    
      export default App;
  • src/App.css

    @import '~antd/dist/antd.css';
      
      .App {
        text-align: center;
      }

實現按需加載(css/js)

  • 使用 eject 命令將全部內建的配置暴露出來

    npm run eject
  • 下載babel-plugin-import(用於按需加載組件代碼和樣式的 babel 插件)

    npm install babel-plugin-import --save-dev
  • 修改配置: config/webpack.config.dev.js

    // Process JS with Babel.
      {
        test: /\.(js|jsx)$/,
        include: paths.appSrc,
        loader: 'babel',
        query: {
      +   plugins: [
      +     ['import', [{ libraryName: "antd", style: 'css' }]],
      +   ],
          // This is a feature of `babel-loader` for webpack (not Babel itself).
          // It enables caching results in ./node_modules/.cache/babel-loader/
          // directory for faster rebuilds.
          cacheDirectory: true
        }
       },
  • 去除引入全量樣式的語句: src/App.css

    @import '~antd/dist/antd.css'
願你成爲終身學習者
相關文章
相關標籤/搜索