2-初識React與JSX

初識 React 與 JSX

[TOC]

加載引入

  • 基于瀏覽器 <script> 的模式
  • 基于自動化的集成環境模式

基于瀏覽器 <script> 的模式

React.js 框架本身包含兩個部分

  • react.js:提供 React.js 核心功能代碼,如:虛擬 dom,組件
  • react-dom.js:提供了與瀏覽器交互的 DOM 功能,如: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>

<u>js/app.js</u>

ReactDOM.render(
    '<div>開課吧</div>',
    document.getElementById('app')
);

ReactDOM.render

ReactDOM.render(element, container[, callback])

element:要渲染的內容

container:要渲染的內容存放容器

callback:渲染后的回調函數

XSS

為了有效的防止 XSS 注入攻擊,React DOM 會在渲染的時候把內容(字符串)進行轉義,所以字符串形式的標簽是不會作為 HTML 標簽進行處理的

編程范式

就是編程的一種模式,比較流行的一些編程范式

  • 命令式編程
  • 聲明式編程
  • 函數式編程
  • ......

命令式編程

告訴計算機怎么做(<u>How?</u>) - 過程

在前面的原生 <u>WebComponent</u> 中,我們 <u>UI</u> 的構建是使用了命令式的編程方式來完成的

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

聲明式編程

告訴計算機我們要什么(<u>What?</u>) - 結果

SELECT * FROM `USER` WHERE `gender`='男' ORDER BY `age` DESC;

上面的 <u>SQL</u> 就是一個典型的聲明式編程,告訴數據庫,我要什么結果,至于怎么查詢出來結果,排序如何實現的過程 <u>SQL</u> 并不關心,由內部(底層)實現

['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>

使用 <u>JSX</u>

JSX 是一個基于 JavaScript + XML 的一個擴展語法

  • 它可以作為 使用
  • 它并不是 字符串
  • 它也不是 HTML
  • 它可以配合 JavaScript 表達式 一起使用

<u>js/app.js</u>

ReactDOM.render(
    <div>開課吧</div>,
    document.getElementById('app')
);

引入 <u>JSX</u> 解析庫

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

<u>DOM</u> 對象與 <u>Virtual DOM</u>

DOM 對象

瀏覽器會把頁面中的元素映射為 JavaScript 中的對象,在 JavaScript 中通過對這些對象的訪問來獲取頁面中對應元素及其內容。同時,對這些對象進行某些操作,又會反饋到頁面中對應的元素上面。

但是,原生 JavaScript DOM 對象內容和結構太復雜,有很多的特性是我們平時很少用到的,而且我們對對象的操作會立即反饋到頁面(渲染),影響性能

虛擬 DOM

virtual DOM,參考原生 DOM 對象構建的一個對象,它的結構足夠簡單,同時優化渲染邏輯,減少變化帶來的渲染性能影響

const App = (
    <div>
        <h1>開課吧</h1>
        <p>web前端高級工程師</p>
    </div>
);

生成的 virtual DOM 結構如下:

[圖片上傳失敗...(image-cc2126-1613962459253)]

<u>JSX</u> 語法規則

結構

每一個獨立 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>
);

在 <u>JSX</u> 中嵌入表達式

JXS 中可以使用 <u>{表達式}</u> 嵌入JavaScript表達式

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

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

<span style="color:red">注意:分清楚 <u>表達式</u> 與 <u>語句</u> 的區別,<u>if</u>、<u>for</u>、<u>while</u> 這些都是語句,<u>JSX</u> 不支持語句</span>

<h1>{if (true) {...}</h1> // 錯誤

<u>JSX</u> 語法示例

JSX 中,表達式輸出的內容類型與使用位置也有一些區別

<u>JSX</u> 中的注釋

<div>
    {/*注釋*/}
    {/*
            多行注釋
    */}
</div>

輸出數據類型

  • <u>字符串</u>、<u>數字</u>:原樣輸出
  • <u>數組</u>:轉成字符串,數組.join('')
    • 使用 <u>空字符串</u> 而不是默認的 <u>逗號</u> 連接
  • <u>其它對象</u>不能直接輸出
  • <u>布爾值</u>、<u>空</u>、<u>未定義</u> 會被忽略

在屬性上使用 <u>表達式</u>

<u>JSX</u> 中的表達式也可以使用在屬性上,但是使用的時候需要注意

  • 當在屬性中使用 <u>{}</u> 的時候,不要使用引號包含
let id = 'kaikeba';

// 錯誤
const App = (
    <div id="{id}"></div>
);

// 正確
const App = (
    <div id={id}></div>
);
  • <u>JSX</u> 更偏向 <u>JavaScript</u>, 所以對于一些特殊的屬性,使用的是 <u>JavaScript</u> 中的屬性名風格
// 錯誤
const App = (
    <div class="box1"></div>
);
// 正確
const App = (
    <div className="box1"></div>
);
  • 為了更加方法的操作元素的 <u>style</u>,針對 <u>style</u> 這個屬性有特殊的處理
const App = (
    <div style={{width: '100px', height: '100px', color:'red'}}></div>
);

這里的兩個 <u>{{}}</u> ,外部的大括號表示的是前面說的表達式語法中的大括號,里面的大括號是表示對象的大括號

let skin = {width: '100px', height: '100px', color:'red'};
const App = (
    <div style={skin}></div>
);

列表渲染

如果需要渲染一組數據,我們可以通過遍歷(數組遍歷、對象變量……)等操作,返回一組 <u>JSX</u>

數據

let zMouse = {
  name: '子鼠',
  gender: '男',
  skills: ['JavaScript', 'Node.js'],
  interests: ['音樂', '足球', '編程']
};
數組
function getSkills() {
  return (
    <ul>
      {zMouse.skills.map(skill => <li>{skill}</li>)}
    </ul>
  );
}
const App = (
    <div>{getSkills()}</div>
);
// 或者
const App = (
    <div>
            <ul>
            {zMouse.skills.map(skill => <li>{skill}</li>)}
            </ul>
    </div>
);
對象
function getKeys() {
    let arr = [];
    for (let k in zMouse) {
        arr.push(<li>{k}</li>);
    }
    return arr;
}

const App = (
    <div>
            <ul>
            {getKeys()}
            </ul>
    </div>
);
// 或者
const App = (
    <div>
            <ul>
            {Object.keys(zMouse).map(key => <li>{key}</li>)}
            </ul>
    </div>
);
key

默認情況下,React 從性能上考慮,會盡可能的復用結構,針對 <u>同組可變列表</u> 結構,為了避免出現某些方面的問題,通常會給每一個列表添加一個 <u>唯一的 key</u>

<ul>
{[{id:1,name:'zMouse',id:2,name:'MT'}].map(user => <li key={user.id}>{user.name}</li>)}
</ul>

<span style="color:red">注意:key 的值不推薦使用數組的下標,具體原因,章節最后詳細解釋</span>

條件渲染

function moreInterests() {
    if (zMouse.interests.length > 2) {
        return <a href="#">更多</a>
    }
}
const App = (
        <div>
            愛好:{zMouse.interests.map(interest=>{
            return <span style={{marginRight:"10px"}}>{interest}</span>
        })}
        {moreInterests()}
    </div>
);
三元運算符
const App = (
        <div>
            愛好:{zMouse.interests.map(interest=>{
            return <span style={{marginRight:"10px"}}>{interest}</span>
        })}
        {zMouse.interests.length > 2 ? <a href="#">更多</a> : null}
    </div>
);
與或運算符
const App = (
        <div>
            愛好:{zMouse.interests.map(interest=>{
            return <span style={{marginRight:"10px"}}>{interest}</span>
        })}
                {zMouse.interests.length > 2 && <a href="#">更多</a>}
                {zMouse.interests.length < 4 || <a href="#">更多</a>}
    </div>
);
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容