React 0基礎學習路線(1)—初識React和JSX

重點大綱提煉

  • JSX
    • 聲明式UI編寫
    • 語法
      • 怎麼輸出數據
      • {表達式}
      • 針對不同的數據輸出會有不同的表現
      • 列表
      • 邏輯輸出

React介紹

img

  一個用於構建用戶界面的 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元素等。

image-20200530211511587
// 類似模板引擎的render,是渲染界面用的!
// 第一個參數:渲染的內容 第二個參數:渲染內容放置在頁面的什麼位置
ReactDOM.render(
    '<div>我要渲染的內容</div>',
    // '我要渲染的內容',
    document.querySelector('#app')
);

  發現達不到預期結果,它只能最終解析爲字符串!爲什麼這樣設計呢?參考下面的**XSS**

  爲了更方便輸出html以及爲後續的一些功能作準備,如組件化、虛擬dom,在這裏它提供了一套新的模板語法。

image-20200530211723370
<!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>

image-20200628150518884

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 結構如下:

image-20200628144131129

<!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了。

image-20200628151408417

<!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對象東西特別多,非常複雜。實際上在做模板渲染的時候,壓根不需要如此多的信息。我們最需要關注的幾個信息:

  1. 啥標籤?
  2. 標籤類型:文本/元素
  3. 標籤屬性
  4. 標籤嵌套內容

  我們通過模板寫的標籤,直接會被react轉換爲虛擬dom。因爲真實dom比較大,一定程度上會影響性能等因素。畢竟操作dom的開銷是比較大的,所以jsx首先做的事情,就是把模板轉化成虛擬dom。在必要的時候,再把虛擬dom變爲真實dom。在這個整個過程當中,對頁面當中一些操作,如對數據的一些變更,都會使模板發生變化。模板變化以後,react會判斷哪些地方是需要更新的,哪些地方樹不需要更新的,而且判斷是基於很小的虛擬dom進行的,所以開銷相對於原生js而言很小。即用一個很小的對象,降低dom頻繁更新頻繁操作帶來的性能損耗問題。

image-20200628151622192

  虛擬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是標籤裏面嵌套的內容。

image-20200628153926775

  我們仔細觀察,裏面的嵌套的children,有時一個虛擬dom,是層層嵌套的結構。

image-20200628154253184

  最終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>

image-20200628155727885

<!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>

image-20200628155937811

JSX 中嵌入表達式(插值表達式)

  在 JXS 中可以使用 {表達式} 嵌入JavaScript表達式(與VUE一樣)

表達式:產生值的一組代碼的集合

  • 變量
  • 算術運算
  • 函數調用
  • ……
let name = '開發崗位';
let title = 'web前端高級工程師';
const App = (
    <div>
        <h1>{name}</h1>
        <p>{title}</p>
    </div>
);

注意:分清楚 表達式語句 的區別,ifforwhile 這些都是語句,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>

image-20200628160227159

  還可以用算術運算表達式嵌入:

<!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>

image-20200628160406248

  除此之外,還有函數調用

<!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>

image-20200628160535244

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(''),使用空字符代替了逗號連接。

image-20200628160724104

['a','b','c'].toString()

image-20200628160914195

  假如想輸出對象:

<!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>

報錯了!

image-20200628161113602

如何把數組輸出ulli的形式:

<!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的緣故,暫時放下。

image-20200628162237722

這個方法我們還可以進行簡化:

function renderList() {
    return list.map( item => <li>{item}</li> );
}

image-20200628162237722

其實沒必要套函數,直接用就行。

<!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>

image-20200628162237722

在屬性上使用 表達式

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>

image-20200628163420367

  • 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>

image-20200628163931622

列表渲染

  如果需要渲染一組數據,我們可以通過遍歷(數組遍歷、對象變量……)等操作,返回一組 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>

image-20200628145358935

對象
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>

image-20200628145625654

以上代碼,實際都會警告,實際是我們沒有加key。

image-20200628145658014

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>

image-20200628164841414

<!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>

image-20200628165125226

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


(後續待補充)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章