文章目錄
重點大綱提煉
- JSX
- 聲明式UI編寫
- 語法
- 怎麼輸出數據
- {表達式}
- 針對不同的數據輸出會有不同的表現
- 列表
- 邏輯輸出
React介紹
一個用於構建用戶界面的 JavaScript 庫
起源
React
起源於 Facebook
的內部項目,因爲該公司對市場上所有 JavaScript MVC 框架,都不滿意,就決定自己寫一套,做出來以後,發現這套東西很好用,就在2013年5月開源了,隨後越來越多人開始關注和使用 React
,慢慢的 React
就成爲了當前最流行的前端開發框架之一。
特點
React
採用了聲明式編程範式,可以更加方便的構建UI
應用- 內部封裝更加高效的與底層
DOM
進行交互的邏輯,提高性能的同時也能幫助我們更加專注於業務 - 可以很好的接納其它框架或庫與其進行配合
React 全家桶
React
: 提供框架(庫)核心功能,如組件
、虛擬DOM
等create-react-app
: 腳手架,提供一套用於快速 構建和打包React
項目的工具react-router
: 基於React
的路由庫redux、react-redux
: 狀態管理庫
初識 React 與 JSX
加載引入
- 基於瀏覽器 <script> 的模式
- 基於自動化的集成環境模式
基於瀏覽器 script
的模式
React.js 框架本身包含兩個部分
- react.js:提供 React.js 核心功能代碼,如:虛擬 dom,組件
- 封裝了很多底層的函數,核心類,但這些通通都與環境無關,跟操作瀏覽器原生app無關的一些東西,而是核心的東西。
- 除此之外還提供了react dom,它提供了對不同環境的封裝,比如dom操作。即主件這個東西,本身是與瀏覽器無關的,它只是定義了一個主件結構,放在覈心庫中。像虛擬dom,通通與瀏覽器無關,無論在瀏覽器中用,還是在原生app中用,它都有組件的概念和組件的代碼
- react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼(React不只是僅僅在瀏覽器中去應用,<React Native>同時還可以運用在手機端
- react-dom.js:提供了與瀏覽器交互的 DOM 功能,如:dom 渲染
- 基於web的,封裝與瀏覽器打交道的相關代碼,渲染,事件
起手式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<script src="./js/react.development.js"></script>
<script src="./js/react-dom.development.js"></script>
<script src="./src/1.js"></script>
<script>
// 類似模板引擎的render,是渲染界面用的!
// 第一個參數:渲染的內容 第二個參數:渲染內容放置在頁面的什麼位置
ReactDOM.render(
//'<div>我要渲染的內容</div>',
'我要渲染的內容',
document.querySelector('#app')
);
</script>
</body>
</html>
我們不能僅僅渲染字符串,而需要渲染html元素等。
// 類似模板引擎的render,是渲染界面用的!
// 第一個參數:渲染的內容 第二個參數:渲染內容放置在頁面的什麼位置
ReactDOM.render(
'<div>我要渲染的內容</div>',
// '我要渲染的內容',
document.querySelector('#app')
);
發現達不到預期結果,它只能最終解析爲字符串!爲什麼這樣設計呢?參考下面的**XSS
**
爲了更方便輸出html以及爲後續的一些功能作準備,如組件化、虛擬dom,在這裏它提供了一套新的模板語法。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="./js/react.production.min.js"></script>
<script src="./js/react-dom.production.min.js"></script>
<script src="js/app.js"></script>
</body>
</html>
js/app.js
ReactDOM.render(
'<div>我要渲染的內容</div>',
document.getElementById('app')
);
ReactDOM.render
ReactDOM.render(element, container[, callback])
element:要渲染的內容
container:要渲染的內容存放容器
callback:渲染後的回調函數
XSS
爲了有效的防止 XSS
注入攻擊,React DOM
會在渲染的時候把內容(字符串)進行轉義,所以字符串形式的標籤是不會作爲 HTML
標籤進行處理的
編程範式
就是編程的一種模式,比較流行的一些編程範式
- 命令式編程
- 聲明式編程
- 函數式編程
- …
命令式編程
告訴計算機怎麼做(How?) - 過程
在前面所學的原生 WebComponent 中,我們 UI 的構建是使用了命令式的編程方式來完成的
let shadow = this.attachShadow({mode: 'open'});
let style = document.createElement('style');
style.textContent = `span {color:red}`;
let span = document.createElement('span');
span.innerHTML = '我是自定義元素的內容';
span.classList.add('cred');
shadow.appendChild(style);
shadow.appendChild(span);
聲明式編程
告訴計算機我們要什麼(What?) - 結果
SELECT * FROM `USER` WHERE `gender`='男' ORDER BY `age` DESC;
上面的 SQL 就是一個典型的聲明式編程,告訴數據庫,我要什麼結果,至於怎麼查詢出來結果,排序如何實現的過程 SQL 並不關心,由內部(底層)實現
['k',1,2,'k',true,'b'].filter(v => Number.isFinite(v)).map(v=>v*10).reduce((c, v)=>c + v, 0);
React.js 中的聲明式 UI
<span className="cred">我是自定義元素的內容</span>
使用 JSX
JSX
是一個基於 JavaScript
+ XML
的一個擴展語法
- 它可以作爲
值
使用 - 它並不是
字符串
- 它也不是
HTML
- 它可以配合
JavaScript 表達式
一起使用
js/app.js
ReactDOM.render(
<div>我要渲染的內容</div>,
document.getElementById('app')
);
引入 JSX 解析庫
babel-standalone.js:在瀏覽器中處理 JSX
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel" src="js/app.js"></script>
注意:如果包含或引入的代碼中包含
JSX
,需要設置script
標籤的type
屬性爲:text/babel
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts等語法 -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
/**
* JSX
* JavaScript + XML
*/
ReactDOM.render(
<div>我要渲染的內容</div>,
document.querySelector('#app')
);
</script>
</body>
</html>
DOM 對象與 Virtual DOM
JSX 通過編譯器會最終轉成一個對象給我們 - VDOM(虛擬DOM)
DOM 對象
瀏覽器會把頁面中的元素映射爲 JavaScript 中的對象,在 JavaScript 中通過對這些對象的訪問來獲取頁面中對應元素及其內容。同時,對這些對象進行某些操作,又會反饋到頁面中對應的元素上面。
但是,原生 JavaScript DOM 對象內容和結構太複雜,有很多的特性是我們平時很少用到的,而且我們對對象的操作會立即反饋到頁面(渲染),影響性能
虛擬 DOM
virtual DOM,參考原生 DOM 對象構建的一個對象,它的結構足夠簡單,同時優化渲染邏輯,減少變化帶來的渲染性能影響
const App = (
<div>
<h1>開發</h1>
<p>web前端高級工程師</p>
</div>
);
生成的 virtual DOM 結構如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
/**
* JSX
* JavaScript + XML
*
* JSX 通過編譯器會最終轉成一個對象給我們 - VDOM(虛擬DOM)
*/
let div = <div>我要渲染的內容</div>;
console.log(div);
ReactDOM.render(
div,
document.querySelector("#app")
);
</script>
</body>
</html>
這就是實際上的虛擬dom了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
/**
* JSX
* JavaScript + XML
*
* JSX 通過編譯器會最終轉成一個對象給我們 - VDOM(虛擬DOM)
*/
let div = <div>我要渲染的內容</div>;
let appElement = document.querySelector('#app');
console.dir(appElement);
console.log(div);
ReactDOM.render(
div,
// document.querySelector("#app")
appElement
);
</script>
</body>
</html>
我們這樣就看到真實dom元素了,它是頁面中真實存在的dom對象。這個對象表示了頁面的一些元素的信息,但是原生當中的dom對象東西特別多,非常複雜。實際上在做模板渲染的時候,壓根不需要如此多的信息。我們最需要關注的幾個信息:
- 啥標籤?
- 標籤類型:文本/元素
- 標籤屬性
- 標籤嵌套內容
我們通過模板寫的標籤,直接會被react轉換爲虛擬dom。因爲真實dom比較大,一定程度上會影響性能等因素。畢竟操作dom的開銷是比較大的,所以jsx首先做的事情,就是把模板轉化成虛擬dom。在必要的時候,再把虛擬dom變爲真實dom。在這個整個過程當中,對頁面當中一些操作,如對數據的一些變更,都會使模板發生變化。模板變化以後,react會判斷哪些地方是需要更新的,哪些地方樹不需要更新的,而且判斷是基於很小的虛擬dom進行的,所以開銷相對於原生js而言很小。即用一個很小的對象,降低dom頻繁更新頻繁操作帶來的性能損耗問題。
虛擬dom大致結構:
let div = <div id="div1" style={{color: 'red'}}><span>我要渲染的內容</span><strong>123</strong></div>;
{
type: 'div',
props: {id: 'div1'}
.....(存放標籤中的各個屬性)
}
該對象的props
有一個id
爲’div1’。
style
是一個對象屬性,存放樣式。
children
是標籤裏面嵌套的內容。
我們仔細觀察,裏面的嵌套的children,有時一個虛擬dom,是層層嵌套的結構。
最終ReactDOM.render
利用虛擬dom的結構去渲染頁面,它會遍歷該對象,首先看type,根據type如果是div就利用原生js創建一個div。緊接着再看它的props下的children,就這樣層層遞歸的去創建。最後將創建好的真實dom渲染到指定的appElement
元素裏面去。
JSX 語法規則
結構
每一個獨立 JSX
結構的頂層有且只能有一個頂級父元素
// 錯誤
const App = (
<div>
<h1>開發</h1>
<p>web前端高級工程師</p>
</div>
<div>第二個</div>
);
// 正確
const App = (
<div>
<div>
<h1>開發</h1>
<p>web前端高級工程師</p>
</div>
<div>第二個</div>
</div>
);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
// 正確結構
let div1 = <div>
這是內容1
</div>;
let div2 = <div>
這是內容2
</div>;
// div3的結構是錯誤的
let div3 = <div>111</div><div>222</div>;
ReactDOM.render(
div,
appElement
);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
// 正確結構
let div1 = <div>
這是內容1
</div>;
let div2 = <div>
這是內容2
</div>;
// div3的結構是錯誤的
// let div3 = <div>111</div><div>222</div>;
ReactDOM.render(
<div>
{div1}{div2}
</div>,
appElement
);
</script>
</body>
</html>
在 JSX 中嵌入表達式(插值表達式)
在 JXS
中可以使用 {表達式} 嵌入JavaScript
表達式(與VUE一樣)
表達式:產生值的一組代碼的集合
- 變量
- 算術運算
- 函數調用
- ……
let name = '開發崗位';
let title = 'web前端高級工程師';
const App = (
<div>
<h1>{name}</h1>
<p>{title}</p>
</div>
);
注意:分清楚 表達式 與 語句 的區別,if、for、while 這些都是語句,JSX 不支持語句
<h1>{if (true) {...}</h1> // 錯誤
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '開發崗位';
let title = 'web前端高級工程師';
// 正確結構
let div1 = <div>
這是內容1 :{name}
</div>;
let div2 = <div>
這是內容2 :{title}
</div>;
// div3的結構是錯誤的
// let div3 = <div>111</div><div>222</div>;
ReactDOM.render(
<div>
{div1}{div2}
</div>,
appElement
);
</script>
</body>
</html>
還可以用算術運算表達式嵌入:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '開發崗位';
let title = 'web前端高級工程師';
// 正確結構
let div1 = <div>
這是內容1 :{name}
</div>;
let div2 = <div>
這是內容2 :{title}
</div>;
// div3的結構是錯誤的
// let div3 = <div>111</div><div>222</div>;
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
</div>,
appElement
);
</script>
</body>
</html>
除此之外,還有函數調用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '開發崗位';
let title = 'web前端高級工程師';
// 正確結構
let div1 = <div>
這是內容1 :{name}
</div>;
let div2 = <div>
這是內容2 :{title}
</div>;
// div3的結構是錯誤的
// let div3 = <div>111</div><div>222</div>;
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
<hr />
{Math.random()}
</div>,
appElement
);
</script>
</body>
</html>
JSX 語法示例
在 JSX
中,表達式輸出的內容類型與使用位置也有一些區別
JSX 中的註釋
<div>
{/*註釋*/}
{/*
多行註釋
*/}
</div>
輸出數據類型
- 字符串、數字:原樣輸出
- 數組:轉成字符串,數組.join(’’)
- 使用 空字符串 而不是默認的 逗號 連接
- 其它對象不能直接輸出
- 布爾值、空、未定義 會被忽略
看一下數組表達式輸出:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '開發崗位';
let title = 'web前端高級工程師';
// 正確結構
let div1 = <div>
這是內容1 :{name}
</div>;
let div2 = <div>
這是內容2 :{title}
</div>;
// div3的結構是錯誤的
// let div3 = <div>111</div><div>222</div>;
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
<hr />
{Math.random()}
<hr />
{['a','b','c']}
</div>,
appElement
);
</script>
</body>
</html>
實際這裏內部調用了類似數組.join('')
,使用空字符代替了逗號連接。
['a','b','c'].toString()
假如想輸出對象:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '開發崗位';
let title = 'web前端高級工程師';
let user = {username: 'ls', gender: '男'};
// 正確結構
let div1 = <div>
這是內容1 :{name}
</div>;
let div2 = <div>
這是內容2 :{title}
</div>;
// div3的結構是錯誤的
// let div3 = <div>111</div><div>222</div>;
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
<hr />
{Math.random()}
<hr />
{['a','b','c']}
<hr />
{user}
</div>,
appElement
);
</script>
</body>
</html>
報錯了!
如何把數組輸出ul
和li
的形式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '開發崗位';
let title = 'web前端高級工程師';
let user = {username: 'ls', gender: '男'};
let list = ['aaa', 'bbb', 'ccc'];
// 正確結構
let div1 = <div>
這是內容1 :{name}
</div>;
let div2 = <div>
這是內容2 :{title}
</div>;
// div3的結構是錯誤的
// let div3 = <div>111</div><div>222</div>;
function renderList() {
let lis = [];
list.forEach( item => {
lis.push(<li>{item}</li>);
} );
// [<li>aaa</li>,<li>bbb</li>,<li>ccc</li>]
return lis;
}
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
<hr />
{Math.random()}
<hr />
{['a','b','c']}
<hr />
{/*user*/}
<hr />
<ul>
{renderList()}
</ul>
</div>,
appElement
);
</script>
</body>
</html>
警告是key
的緣故,暫時放下。
這個方法我們還可以進行簡化:
function renderList() {
return list.map( item => <li>{item}</li> );
}
其實沒必要套函數,直接用就行。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '開發崗位';
let title = 'web前端高級工程師';
let user = {username: 'ls', gender: '男'};
let list = ['aaa', 'bbb', 'ccc'];
// 正確結構
let div1 = <div>
這是內容1 :{name}
</div>;
let div2 = <div>
這是內容2 :{title}
</div>;
// div3的結構是錯誤的
// let div3 = <div>111</div><div>222</div>;
// function renderList() {
// let lis = [];
//
// list.forEach( item => {
// lis.push(<li>{item}</li>);
// } );
//
// // [<li>aaa</li>,<li>bbb</li>,<li>ccc</li>]
// return lis;
// }
// function renderList() {
// return list.map( item => <li>{item}</li> );
// }
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
<hr />
{Math.random()}
<hr />
{['a','b','c']}
<hr />
{/*user*/}
<hr />
<ul>
{list.map( item => <li>{item}</li> )}
</ul>
</div>,
appElement
);
</script>
</body>
</html>
在屬性上使用 表達式
JSX 中的表達式也可以使用在屬性上,但是使用的時候需要注意
- 當在屬性中使用 {} 的時候,不要使用引號包含
let id = 'aaaaaa';
// 錯誤
const App = (
<div id="{id}"></div>
);
// 正確
const App = (
<div id={id}></div>
);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '開發崗位';
let title = 'web前端高級工程師';
let user = {username: 'ls', gender: '男'};
let list = ['aaa', 'bbb', 'ccc'];
let divId = 'aaaaa';
// 正確結構
let div1 = <div>
這是內容1 :{name}
</div>;
let div2 = <div>
這是內容2 :{title}
</div>;
// div3的結構是錯誤的
// let div3 = <div>111</div><div>222</div>;
// function renderList() {
// let lis = [];
//
// list.forEach( item => {
// lis.push(<li>{item}</li>);
// } );
//
// // [<li>aaa</li>,<li>bbb</li>,<li>ccc</li>]
// return lis;
// }
// function renderList() {
// return list.map( item => <li>{item}</li> );
// }
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
<hr />
{Math.random()}
<hr />
{['a','b','c']}
<hr />
{/*user*/}
<hr />
<ul>
{list.map( item => <li>{item}</li> )}
</ul>
<hr />
<div id={divId}>CSDN</div>
</div>,
appElement
);
</script>
</body>
</html>
- JSX 更偏向 JavaScript, 所以對於一些特殊的屬性,使用的是 JavaScript 中的屬性名風格
// 錯誤
const App = (
<div class="box1"></div>
);
// 正確
const App = (
<div className="box1"></div>
);
- 爲了更加方法的操作元素的 style,針對 style 這個屬性有特殊的處理
const App = (
<div style={{width: '100px', height: '100px', color:'red'}}></div>
);
這裏的兩個 {{}} ,外部的大括號表示的是前面說的表達式語法中的大括號,裏面的大括號是表示對象的大括號
let skin = {width: '100px', height: '100px', color:'red'};
const App = (
<div style={skin}></div>
);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let name = '開發崗位';
let title = 'web前端高級工程師';
let user = {username: 'ls', gender: '男'};
let list = ['aaa', 'bbb', 'ccc'];
let divId = 'aaaaa';
let style = {color: 'red', background: 'yellow'};
// 正確結構
let div1 = <div>
這是內容1 :{name}
</div>;
let div2 = <div>
這是內容2 :{title}
</div>;
// div3的結構是錯誤的
// let div3 = <div>111</div><div>222</div>;
// function renderList() {
// let lis = [];
//
// list.forEach( item => {
// lis.push(<li>{item}</li>);
// } );
//
// // [<li>aaa</li>,<li>bbb</li>,<li>ccc</li>]
// return lis;
// }
// function renderList() {
// return list.map( item => <li>{item}</li> );
// }
ReactDOM.render(
<div>
{div1}{div2}
<hr />
{1+1}
<hr />
{Math.random()}
<hr />
{['a','b','c']}
<hr />
{/*user*/}
<hr />
<ul>
{list.map( item => <li>{item}</li> )}
</ul>
<hr />
<div id={divId}>CSDN</div>
<hr />
<p style={style}>這是內容</p>
<p style={{color: 'red', background: 'yellow'}}>這是內容</p>
</div>,
appElement
);
</script>
</body>
</html>
列表渲染
如果需要渲染一組數據,我們可以通過遍歷(數組遍歷、對象變量……)等操作,返回一組 JSX
數據
let lisi = {
name: '李四',
gender: '男',
skills: ['JavaScript', 'Node.js'],
interests: ['音樂', '足球', '編程']
};
數組
function getSkills() {
return (
<ul>
{lisi.skills.map(skill => <li>{skill}</li>)}
</ul>
);
}
const App = (
<div>{getSkills()}</div>
);
// 或者
const App = (
<div>
<ul>
{lisi.skills.map(skill => <li>{skill}</li>)}
</ul>
</div>
);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts等語法 -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let lisi = {
name: '李四',
gender: '男',
skills: ['JavaScript', 'Node.js'],
interests: ['音樂', '足球', '編程']
};
function getSkills() {
return (
<ul>
{lisi.skills.map(skill => <li>{skill}</li>)}
</ul>
);
}
const App = (
<div>{getSkills()}</div>
);
ReactDOM.render(
App,
document.querySelector('#app')
);
</script>
</body>
</html>
對象
function getKeys() {
let arr = [];
for (let k in lisi) {
arr.push(<li>{k}</li>);
}
return arr;
}
const App = (
<div>
<ul>
{getKeys()}
</ul>
</div>
);
// 或者
const App = (
<div>
<ul>
{Object.keys(lisi).map(key => <li>{key}</li>)}
</ul>
</div>
);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts等語法 -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let lisi = {
name: '李四',
gender: '男',
skills: ['JavaScript', 'Node.js'],
interests: ['音樂', '足球', '編程']
};
function getKeys() {
let arr = [];
for (let k in lisi) {
arr.push(<li>{k}</li>);
}
return arr;
}
const App = (
<div>
<ul>
{getKeys()}
</ul>
</div>
);
ReactDOM.render(
App,
document.querySelector('#app')
);
</script>
</body>
</html>
以上代碼,實際都會警告,實際是我們沒有加key。
key
默認情況下,React 從性能上考慮,會盡可能的複用結構,針對 同組可變列表 結構,爲了避免出現某些方面的問題,通常會給每一個列表添加一個 唯一的 key
<ul> {[{id:1,name:'lisi',id:2,name:'zhangsan'}].map(user => <li key={user.id}>{user.name}</li>)} </ul>
注意:key 的值不推薦使用數組的下標,具體原因,末尾最後詳細解釋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let list = ['aaa', 'bbb', 'ccc'];
ReactDOM.render(
<ul>
{
list.map( (item) => {
return <li>{item}</li>
})
}
</ul>,
appElement
);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
let list = ['aaa', 'bbb', 'ccc'];
function List() {
return <ul>
{
list.map( (item) => {
return <li><input type="checkbox"/> {item}</li>
})
}
</ul>
}
ReactDOM.render(
<List/>,
appElement
);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<!-- react.js: react的核心庫,提供了組件,輔助函數等與具體環境無關的核心代碼 -->
<script src="./js/react.development.js"></script>
<!-- react-dom.js:封裝與瀏覽器打交道的相關代碼,渲染,事件 -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:語法轉換工具,它可以把一些特定的語法轉成js,比如,jsx,ts -->
<script src="./js/babel.min.js"></script>
<!-- 讓下面的代碼不要直接通過瀏覽器來運行,同時還要指定babel來編譯它們 -->
<script type="text/babel">
let appElement = document.querySelector('#app');
function List(props) {
return <ul>
{
props.data.map( item => {
return <li><input type="checkbox" /> {item}</li>
} )
}
</ul>
}
class App extends React.Component {
constructor() {
super();
this.state = {
list:['aaa', 'bbb', 'ccc']
}
}
render() {
return <div>
<List data={this.state.list} />
<button onClick={() => {
this.setState({
list: this.state.list.sort((a, b) => Math.random() - .5)
})
}}>按鈕</button>
</div>
}
}
ReactDOM.render(
<App />,
appElement
);
</script>
</body>
</html>
發現了奇怪的問題。li
隨機排序後,勾選狀態原地不動。
首先根據傳進去的數據,會渲染頁面li
。當數據發生變化,頁面就會更新。調用this.setState
方法後就表明數據發生了變化,它就會更新與這個數據有關的所有組件。React不會刷新整個頁面,而是更新變化的部分。但是僅僅更新變化的部分,有用嗎?它還考慮了複用問題,爲了讓性能更優,它在這裏儘可能的去複用結構。
要是按照以前的思維,就是產生新的一組li覆蓋舊的li,用innerHtml覆蓋掉全部。
我們仔細觀察,發現變化的是內容。它並沒有把li替換掉,li標籤及裏嵌套的input標籤都不會變,它只變化需要變化的部分。React爲什麼這麼做?完全是爲了複用,爲了不要頻繁地移動、刪除、修改元素,而儘可能地原位複用元素。這樣做的話,是性能優化了,但是對於同組結構(同級別的兄弟節點)而言,就會帶來很大的問題,特別是循環的過程中,循環生成的結構,會帶來很多問題。如這裏的勾選狀態是在html上的,它與數據毫無關係,因此它不會根據數據而重新渲染,即勾選狀態不會隨着數據變化,實際上元素與數據沒有關係。
但是大部分情況下這種特效是很好的,但是在循環列表中,它是有問題的。爲了解決這個問題,達到更高的複用性,就增加了一個key
屬性。key
一定不能寫死,它是用來標識數據與產生元素之間的關聯性的,即它們之間的紐帶和橋樑。但是key
必須胃一值,否則也會識別不出關聯性了。
props.data.map( item => {
return <li key={item}><input type="checkbox" /> {item}</li>
} )
如果不關注這個特性,也可不用key
。如循環一個列表,其上方沒有checkbox
,我們對其進行升序和降序排列,這個時候就沒任何影響,因爲我們需要顯示的也是數據。但是如果數據與節點有關聯的話,就必須使用key
了。
如果我們在這裏使用索引爲key
,也是沒有用的。因爲索引也是可複用的,數據內容變化並不會帶着索引的。
props.data.map( (item, index) => {
return <li key={index}><input type="checkbox" /> {item}</li>
} )
條件渲染
function moreInterests() {
if (lisi.interests.length > 2) {
return <a href="#">更多</a>
}
}
const App = (
<div>
愛好:{lisi.interests.map(interest=>{
return <span style={{marginRight:"10px"}}>{interest}</span>
})}
{moreInterests()}
</div>
);
三元運算符
const App = (
<div>
愛好:{lisi.interests.map(interest=>{
return <span style={{marginRight:"10px"}}>{interest}</span>
})}
{lisi.interests.length > 2 ? <a href="#">更多</a> : null}
</div>
);
與或運算符
const App = (
<div>
愛好:{lisi.interests.map(interest=>{
return <span style={{marginRight:"10px"}}>{interest}</span>
})}
{lisi.interests.length > 2 && <a href="#">更多</a>}
{lisi.interests.length < 4 || <a href="#">更多</a>}
</div>
);
(後續待補充)