1. 程式人生 > 其它 >React學習(四)----- 基於React腳手架的React應用

React學習(四)----- 基於React腳手架的React應用

1、React腳手架

  • 什麼是腳手架???

用來幫助程式設計師快速建立一個基於React庫的模板專案

1) 包含了所有需要的配置(語法檢查、jsx編譯、devServer…)

2) 下載好了所有相關的依賴

3) 可以直接執行一個簡單效果

4)專案的整體技術架構為: react + webpack + es6 + eslint

5)使用腳手架開發專案的特點: 模組化, 元件化, 工程化

  • 腳手架的安裝
    cnpm  install  create-react-app  -g
  • 建立專案
    1、建立專案
         create-react-app hello-react
    
    
    2、進入專案目錄 cd hello-react 3、啟動專案 npm start
  • React腳手架專案結構
    • public ----- 靜態資原始檔夾
      • favicon.ico ----- 網站頁籤圖示
      • index.html ----- 主頁面
        <!DOCTYPE html>
        <html lang="en">
          <head>
            <meta charset="utf-8" />
            <!-- %PUBLIC_URL%代表public資料夾的路徑 相當於./favicon.ico -->
            <
        link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <!-- 開啟理想視口,用於做移動端網頁的適配 --> <meta name="viewport" content="width=device-width, initial-scale=1" /> <!-- 用於配置瀏覽器頁籤 + 位址列的顏色 ,只針對安卓手機瀏覽器(相容性不好,有些機型無效果),不支援ios--> <meta name="theme-color" content="#000000" /> <meta
        name="description" content="Web site created using create-react-app" /> <!-- 只支援ios手機:用於指定網頁新增到手機主屏幕後的圖示 --> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <!-- 應用加殼的配置檔案 --> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <title>React App</title> </head> <body> <!-- 當瀏覽器不支援js時展示的提示資訊 --> <noscript>You need to enable JavaScript to run this app.</noscript> <!-- 容器,掛載虛擬DOM的地方,也就是ReactDOM.render方法的第二個引數 --> <div id="root"></div> </body> </html>
      • robots.txt ----- 爬蟲協議檔案
    • src ----- 原始碼資料夾
      • App.css ----- App元件的樣式
      • App.js ----- App元件
      • App.test.js ----- 用於給App做測試
      • index.css ----- 樣式
      • index.js ----- 入口檔案:React.StrictMode用於檢查App和App的子元件的寫法是否合理
      • logo.svg ----- logo圖
      • reportWebVitals.js ----- 頁面效能分析檔案(需要web-vitals庫的支援)
      • setupTests.js ----- 元件單元測試的檔案(主要jest-dom庫的支援)

2、一個簡單的Hello元件

  • vscode中react外掛的安裝
    ES7 React/Redux/GraphQL/React-Native snippets
  • 樣式的模組化
    • 元件的檔案目錄

    • 將元件的css檔案命名為:index.module.css,在元件jsx中的引入方式為用一個變數接收,並且定義的時候使用差值表示式的方式定義,這樣不會造成樣式汙染
      import { Component } from "react";
      import hello from './index.module.css'
      
      export default class Hello extends Component {
        render() {
          return <h1 className={hello.title}>Hello,React!!!!</h1>;
        }
      }

      不然結果就是:同名的class標籤只會使用後引入的css檔案

  • 功能介面的元件化編碼流程
    1. 拆分元件: 拆分介面,抽取元件
    2. 實現靜態元件: 使用元件實現靜態頁面效果
    3. 實現動態元件
        3.1 動態顯示初始化資料
            3.1.1 資料型別
            3.1.2 資料名稱
            3.1.3 儲存在哪個元件?
        3.2 互動(從繫結事件監聽開始)

3、元件的組合使用(TodoList)

  • 效果圖

  • 知識點
    • 步驟

    • 生成唯一的id值得庫
      cnpm i uuid/nanoid -D//uuid庫比較大,建議選擇nanoid
    • 非父子元件之間的傳值
      1、子傳父、父傳子  即Header傳給App,App傳給List
          (1)子傳父
                  子元件在父元件當做標籤使用
                  1) 子元件this.props.sendData(event.target.value)
                  2) 父元件中的子元件繫結資料
      <Header sendData={this.receiveData} />
                  3) 父元件中的方法
      receiveData = (data) => {
        console.log(data);
      };
          (2)父傳子
                  子元件在父元件當做標籤使用
                  1) 父元件中的子元件繫結資料
      <Header {...this.state}} />
                  2) 在子元件的render方法中使用this.props進行接收
    • checkbox的相關問題
      1、checked屬性必須與onChange事件一起使用;
      2、defaultChecked屬性只有第一次會生效,後效修改將無效;

4、React Ajax

  • 為什麼要引入Ajax???
    1.React本身只關注於介面, 並不包含傳送ajax請求的程式碼
    2.前端應用需要通過ajax請求與後臺進行互動(json資料)
    3.react應用中需要整合第三方ajax庫(或自己封裝)
  • 常用的Ajax請求庫
    1.jQuery: 比較重, 直接操作DOM,會有回撥函式地域的問題,如果需要另外引入不建議使用
    2.axios: 輕量級, 建議使用
       1)封裝XmlHttpRequest物件的ajax
       2)promise風格
       3)可以用在瀏覽器端和node伺服器端
  • 腳手架配置代理(客戶端解決,伺服器的話使用cors)
    • 跨域原因
      http://localhost:3000 -----> http://localhost:5000/students
      原因:由於Ajax引擎的限制,請求可以從3000傳送到5000埠,但是響應的時候被引擎攔截,這個時候我們可以配置代理
          (設定一箇中間人伺服器,也在3000埠執行,而中間伺服器沒有ajax引擎的影響,且伺服器之間無同源策略的影響,可以正常接收響應,接收到響應資料後,由於埠都是
      3000,客戶端直接收到資料)
      本地3000埠執行這一個腳手架,一個伺服器,name腳手架和伺服器由於協議、域名、埠號完全一致,所以不會產生跨域,而本地代理的伺服器與訪問伺服器之間不受同源策略的影響
      因此也可以正常的接收到資料,代理伺服器收到資料後再返回給客戶端,因此解決跨域問題!!!
    • 第一種方式:代理一個伺服器的情況下,多個不允許這麼配置
      • 步驟
        1、修改package.json
        "proxy": "http://localhost:5000"
        2、重啟
        npm start 
        3、修改請求介面
        http://localhost:5000/students -----> http://localhost:3000/students
      • 說明
        1. 優點:配置簡單,前端請求資源時可以不加任何字首。
        2. 缺點:不能配置多個代理。
        3. 工作方式:上述方式配置代理,當請求了3000不存在的資源時,那麼該請求會轉發給5000 (優先匹配前端資源)
    • 第二種方式:代理多個伺服器
      • 步驟
        1. 第一步:建立代理配置檔案
           在src下建立配置檔案:src/setupProxy.js
        2. 編寫setupProxy.js配置具體代理規則:
           // 使用commonjs的語法,引入一個內建外掛  無需安裝
           const proxy = require('http-proxy-middleware')
           
           module.exports = function(app) {
             app.use(
               proxy('/api1', {  //api1是需要轉發的請求(所有帶有/api1字首的請求都會轉發給5000)
                 target: 'http://localhost:5000', //配置轉發目標地址(能返回資料的伺服器地址)
                 changeOrigin: true, //控制伺服器接收到的請求頭中host欄位的值
                 /*
                     changeOrigin設定為true時,伺服器收到的請求頭中的host為:localhost:5000
                     changeOrigin設定為false時,伺服器收到的請求頭中的host為:localhost:3000
                     changeOrigin預設值為false,但我們一般將changeOrigin值設為true
                 */
                 pathRewrite: {'^/api1': ''} //去除請求字首,保證交給後臺伺服器的是正常請求地址(必須配置)  重寫請求路徑
               }),
               proxy('/api2', { 
                 target: 'http://localhost:5001',
                 changeOrigin: true,
                 pathRewrite: {'^/api2': ''}
               })
             )
           }
      • 說明
        1. 優點:可以配置多個代理,可以靈活的控制請求是否走代理。
        2. 缺點:配置繁瑣,前端請求資源時必須加字首。
  • github搜尋案例
    • 效果圖

    • 知識點
      • 連續解構賦值
         const obj = {a:{b:{c:1}}}
         console.log(obj.a.b.c) //1
         const { a: { b: { c } } } = obj
         console.log(c) //1

5、釋出-訂閱機制(適用於任意元件的通訊)

  • 安裝
    cnpm i pubsub-js -S
  • 使用:Search元件傳遞給-----List元件(兄弟元件之間的傳值)
    • List元件訂閱訊息
      import PubSub from 'pubsub-js'
      
      componentDidMount(){
        // 訂閱訊息
        this.token = PubSub.subscribe("updateAppState",(msg,data)=>{
          console.log("list")
          console.log(msg,data)//msg是updateAppState,即事件的名稱,data是釋出的訊息
          this.setState(data) 
        }) 
      } 
      //取消訂閱
      componentWillUnmount(){
        PubSub.unsubscribe(this.token) 
      }
    • Search元件釋出訊息
      import PubSub from 'pubsub-js'
      
      PubSub.publish('updateAppState',{ isFirst: false,isLoading:true })

6、前後端互動的方式

  • jquery/axios
    • 特點
      axios是一個基於Promise,用於瀏覽器和 nodejs 的 HTTP 客戶端,它本身具有以下特徵:
          1)從瀏覽器中建立 XMLHttpRequest
          2)從 node.js 發出 http 請求
          3)支援 Promise API
          4)攔截請求和響應
          5)轉換請求和響應資料
          6)自動轉換JSON資料, 
          7)客戶端支援防止CSRF/XSRF
    • 示例
      import axios from 'axios'
      
      axios.get(`http://localhost:3000/api/search/users?q=${inputValue}`).then((res) => {
        // 請求成功後通知App更新狀態
        updateAppState({isLoading:false,users:res.data.items})
      }).catch(err => {
        updateAppState({isLoading:false,err:err.message})
      })
  • fetch ----- 無需安裝,瀏覽器內建
    • 特點
      fetch:返回的是一個未處理的方法集合,我們可以通過這些方法得到我們想要的資料型別。如果我們想要json格式,就執行res.json(),如果我們想要字串就res.text()
          1)關注分離,沒有將輸入、輸出和用事件來跟蹤的狀態混雜在一個物件裡
          2)更加底層,提供的API豐富(request, response)
          3)脫離了XHR,是ES規範裡新的實現方式
          4)fetch只對網路請求報錯,對400,500都當做成功的請求,需要封裝去處理
          5)fetch預設不會帶cookie,需要新增配置項
          6)fetch不支援abort,不支援超時控制,使用setTimeout及Promise.reject的實現的超時控制並不能阻止請求過程繼續在後臺執行,造成了量的浪費
          7)fetch沒有辦法原生監測請求的進度,而XHR可以
    • 示例
        fetch(`http://localhost:3000/api/search/users?q=${inputValue}`)
            .then(
                (res) => {
                    console.log('聯絡伺服器成功了', res)//是一個綜合各種方法的物件,並不是請求的資料
                    return res.json()
                },
                (error) => {
                  console.log('聯絡伺服器失敗了', error)
                  return new Promise(()=>{})//為了防止斷網走了上一行後,接著走下一個then中的第一個回撥,加上只走上面一行
              })
            .then(
              (res) => {
                console.log("獲取資料成功了",res)
              },
              (error) => {
               console.log('獲取資料失敗了',error)
              })
    • 簡化程式碼後
      fetch(`http://localhost:3000/api/search/users?q=${inputValue}`)
            .then(
                (res) => {
                    console.log('聯絡伺服器成功了', res)//是一個綜合各種方法的物件,並不是請求的資料
                    return res.json()
                }
            )
            .then(
              (res) => {
                console.log("獲取資料成功了",res)
              }
          ).catch(
            (error) => {
               console.log('請求出錯',error)
            }
          )
    • 使用async和await
      try {
           let response = await fetch(`http://localhost:3000/api/search/users?q=${inputValue}`)
           let result = await response.json();
           console.log(result)
       } catch (e) {
           console.log(e)
       }

7、其他問題

暫無

北梔女孩兒