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可以
    • 請求格式
      默認是get請求,如果需要向后端發送數據,則直接在地址后面做拼接
      當請求post方式時:
      fetch(url,
          {
                method:"post",
                body: JSON.stringify(obj),
                headers : {//必須要寫
                     "Content-type" : "application/json";
                     "credentials": 'include'//攜帶cookie進行提交
                }
         }).then((res)=>res.json()).then((data)=>{})
    • 示例:默認為get請求
        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、其他問題

     暫無

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM