前端(八):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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...