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庫的支持)
- public ----- 靜態資源文件夾
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文件
- 將組件的css文件命名為:index.module.css,在組件jsx中的引入方式為用一個變量接收,並且定義的時候使用差值表達式的方式定義,這樣不會造成樣式污染;
- 功能界面的組件化編碼流程
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屬性只有第一次會生效,后效修改將無效;
- 生成唯一的id值得庫
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 })
- List組件訂閱消息
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、其他問題
暫無