前端(八):react基礎

来源:https://www.cnblogs.com/kuaizifeng/archive/2018/07/31/9388292.html
-Advertisement-
Play Games

以前只使用django和jquery做小項目開發,所以決定搞一搞react框架。React 特點:聲明式設計、虛擬DOM、JSX、組件、數據驅動。 一、環境搭建 1.安裝npm、cnpm 2.安裝react全家桶 3.文件目錄結構 項目啟動時,會載入public下的index.html文件,併進而執 ...


  以前只使用django和jquery做小項目開發,所以決定搞一搞react框架。React 特點:聲明式設計、虛擬DOM、JSX、組件、數據驅動。

一、環境搭建

  1.安裝npm、cnpm

# 安裝node.js 從而安裝npm,它會在當前用戶家目錄下生成node_moudules文件夾,來對npm安裝的全局第三方包進行管理
brew install node

# 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,從而完成整個頁面的渲染。

二、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.js。

  1.ReactDOM.render

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

  2.React.Component

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

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

  組件內部可以聲明參數,無論是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'));

  4.靜態數據傳遞--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}/>

  5.動態數據交互--state

  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'));

  6.事件綁定

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

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

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

  鑒於js中沒有局部作用域只有函數作用域,所以如果直接寫onClick={this.addPerson}時,this指的就是windo對象。用一層函數包裹時,this對象指的就是這個函數。

  其它的做法有兩種:

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

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

  其次可以用箭頭函數來聲明addPerson函數,本質上和上面使用的方法一樣:

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

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

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

  7.條件渲染

  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包裹。

  8、組件的生命周期

  組件的聲明周期可分成三個狀態:Mounting,已插入真實 DOM;Updating,正在被重新渲染;Unmounting:已移出真實 DOM。如下圖所示(本圖根據Rosen老師示例改寫)。

  

  各個函數的釋義(摘自菜鳥教程):

  componentWillMount 在渲染前調用,在客戶端也在服務端。

  componentDidMount : 在第一次渲染後調用,只在客戶端。之後組件已經生成了對應的DOM結構,可以通過this.getDOMNode()來進行訪問。 如果你想和其他JavaScript框架一起使用,可以在這個方法中調用setTimeout, setInterval或者發送AJAX請求等操作(防止異部操作阻塞UI)。

  componentWillReceiveProps 在組件接收到一個新的 prop (更新後)時被調用。這個方法在初始化render時不會被調用。

  shouldComponentUpdate 返回一個布爾值。在組件接收到新的props或者state時被調用。在初始化時或者使用forceUpdate時不被調用。
可以在你確認不需要更新組件時使用。

  componentWillUpdate在組件接收到新的props或者state但還沒有render時被調用。在初始化時不會被調用。

  componentDidUpdate 在組件完成更新後立即調用。在初始化時不會被調用。

  componentWillUnmount在組件從 DOM 中移除的時候立刻被調用。

  9、綜合:使用component請求後臺數據並交給組件

  在my-app下建立server/server.js文件,啟動一個後端服務:

const express = require('express');

const app = express();
app.get("/data", function (req, res) {
res.json({"name": "old monkey", "age": 5000})
});
app.listen(3002, function () {
console.log("Node app start at port 3002.")
});

  Terminal啟動該服務: node server/server.js。此時可以訪問http://localhost:3002/data來獲取json數據。 

  安裝axios: cnpm install axios --save。併在package.json的配置文件中添加"proxy"配置,讓它轉換埠到3002:

// package.json
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"axios": "^0.18.0",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-scripts": "1.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:3002"
}

  在src/index.js中寫組件:

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

class App extends React.Component{
constructor(props){
super(props);
this.state = {name: "monkey", age: 100}

}
  // 在component內部使用ajax請求數據,並通過setState傳遞給App。
componentDidMount(){
axios.get("/data").then(res=>{
if(res.status === 200){
console.log(res);
this.setState({name: res.data.name, age: res.data.age});
}
}, err=>{
console.log(err);
})
}
addAge(){
this.setState({age: this.state.age + 1})
};
decAge(){
this.setState({age: this.state.age - 1})
}
render (){
const style={
display: "inline-block",
width: "150px",
height: "40px",
backgroundColor: "rgb(173, 173, 173)",
color: "white",
marginRight: "20px"
};
return (
<div>
<h2>this {this.state.name } is { this.state.age } years old.</h2>
<button style={style} onClick={()=>this.addAge()}>增加一歲</button>
<button style={style} onClick={()=>this.decAge()}>減少一歲</button>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));

三、redux、redux-thunk與react-redux

  react本身能夠完成動態數據的監聽和更新,如果不是必要可以不適用redux。

  安裝redux: cnpm install redux --save。

  1.react基本用法

  redux是獨立的用於狀態管理的第三方包,它建立狀態機來對單項數據進行管理。

  上圖是個人粗淺的理解。用代碼驗證一下:

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from "redux";

function reducer(state={name: "monkey", age: 5000}, action){
switch (action.type){
case "add":
state.age ++;
return state;
case "dec":
if (state.age <= 4995){
state.name = "small monkey";
}
state.age --;
return state;
default:
return state;
}
}
const store = createStore(reducer);
const add = {type: "add"}, dec={type: "dec"};


class App extends React.Component{
render (){
const style={
display: "inline-block",
width: "150px",
height: "40px",
backgroundColor: "rgb(173, 173, 173)",
color: "white",
marginRight: "20px"
};
const store = this.props.store;
// console.log(store.getState());
const obj = store.getState();
// console.log(obj);
return (
<div>
<h2>this { obj.name } is { obj.age } years old.</h2>
<button style={style} onClick={()=>store.dispatch(this.props.add)}>增加一歲</button>
<button style={style} onClick={()=>store.dispatch(this.props.dec)}>減少一歲</button>
</div>
)
}
}
function render() {
ReactDOM.render(<App store={store} add={ add } dec={ dec } />, document.getElementById('root'));
}
render();
store.subscribe(render);

  因為action必須是個對象,所以只能寫成add = {type: "add"}的形式,而不能直接寫參數"add"。同樣地,在reducer中寫switch時將action.type作為參數。

  action和state一一對應,要使用action必須要在reducer里聲明。

  redux沒有用state來實現動態數據更新,而是通過props來傳遞數據,因此在組件內部只能通過props獲取store,以及store.getState()獲取state。

  redux將ReactDOM.render進行了一次封裝來設置監聽。

  redux對數據和組件進行瞭解耦,因而可以進行文件拆分。

  把action寫成函數的形式:

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from "redux";

const Add = "add", Dec="dec";
function reducer(state={name: "monkey", age: 5000}, action){
switch (action.type){
case Add:
state.age ++;
if (state.age > 5005){
state.name = "old monkey";
}
return state;
case Dec:
if (state.age <= 4995){
state.name = "small monkey";
}
state.age --;
return state;
default:
return state;
}
}
const store = createStore(reducer);
class App extends React.Component{
render (){
const style={
display: "inline-block",
width: "150px",
height: "40px",
backgroundColor: "rgb(173, 173, 173)",
color: "white",
marginRight: "20px"
};
const store = this.props.store;
const state = store.getState();
return (
<div>
<h2>this { state.name } is { state.age } years old.</h2>
<button style={style} onClick={()=>store.dispatch(add())}>增加一歲</button>
<button style={style} onClick={()=>store.dispatch(dec())}>減少一歲</button>
</div>
)
}
}
function render() {
ReactDOM.render(<App store={store} add={ add } dec={ dec } />, document.getElementById('root'));
}
render();
store.subscribe(render);

   2.react非同步

  當一個父組件中有多個子組件時,如果每一個組件發生狀態變化,store都要重新渲染一遍。使用非同步可以只重新渲染髮生狀態變化的組件。

  安裝redux和thunk的中間件redux-thunk:cnpm install redux-thunk。引入兩個函數,並修改createStore如下,其餘代碼保持不變:

import { createStore, applyMiddleware } from "redux";
import thunk from 'redux-thunk';
	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 淺談JS嚴格模式 簡介 何為嚴格模式?嚴格模式(strict mode)即在嚴格的條件下運行,在嚴格模式下,很多正常情況下不會報錯的問題語句,將會報錯並阻止運行。 但是,嚴格模式可以顯著提高代碼的健壯性,比如JS經常被人詬病的隱式創建全局變數,在嚴格模式下就會阻止運行。 總的來說,引入嚴格模式雖然會 ...
  • 基本操作(上) 本章節簡介: vue的安裝 vue實例創建 數據綁定渲染 表單數據雙向綁定 事件處理 安裝 安裝方式有三種: 一、vue官網直接下載 http://vuejs.org/js/vue.min.js 二、使用CDN方法 二、使用node.js的npm包管理工具下載 Vue實例 vue實例 ...
  • 今天介紹 怎麼編譯 的各種函數和語法。敲黑板: 這是 版本哦, 有一些不同於 的地方。 " 本節課源碼" " 所有課程源碼" 1. 瞭解 說起編譯 ,就必須提一下 和相關的技術生態: 1. : 負責 es6 語法轉化 2. : 包含 es6、7 等版本的語法轉化規則 3. : es6 內置方法和函數 ...
  • 首先定義好樣式,利用v-for中的index值,然後綁定樣式來實現隔行變色效果。 以下為完整代碼,很簡單,但也是個技巧。 ...
  • Android4.4(KitKat)開始,使用Chrome開發者工具可以幫助我們在原生的Android應用中遠程調試WebView網頁內容。具體步驟如下: (1)設置Webview調試模式 可以在Activity的init進行如下設置,WebView類包含一個公共靜態方法,可應用於項目中的所有Web ...
  • "github 地址 https://github.com/iocool/antminDatePicker" 最近在做支付寶小程式(以下簡稱小程式)開發,發現小程式的日期選擇組件很不好用,比如安卓和IOS設備上,樣式明顯不同,因為小程式調用該組件是調用系統原生組件,所以會有一定的差異,另外,小程式提 ...
  • <html><head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head><body> 😁😁😁😁<br/>IP:192.168.0.1 </body></html> 在Microsoft E ...
  • 最近學習css發現了高度塌陷時候要清除浮動,為了理解清楚浮動原理,網上找了不少資料,發現都寫的不是很清楚,而且都是一模一樣的內容,我在里分享一下我對清楚浮動原理的理解, 如果你已經很瞭解什麼是浮動和浮動的效果你可以直接跳轉到三.如何清除浮動(重點)閱讀 一.什麼是浮動首先我們需要知道定位 元素在頁面 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...