前言
上一篇介紹了Reactjs的項目目錄結構以及他的工作模式。這篇文章將會通過閱讀官方文檔,學習Reactjs的語法,邏輯,思想等內容。
文章目錄
1、JSX
2、元素
3、組件
一、JSX
1、JSX
前面我們瞭解到React是通過js來構造html,實際上React就是通過JSX來渲染元素,那麼什麼是JSX,它跟JS和HTML有什麼關聯呢?
2、JSX簡介
JSX(JavaScript XML)是 js 內定義的一套類 XML 語法,可以解析出目標 js 代碼,顛覆傳統 js 寫法。初接觸JSX的語法,可能會讓人聯想到html模板語言,其實JSX做的工作與HTML所做的工作有一定的相似之處,不用的地方在於,HTML 由瀏覽器解析,而 JSX 是由 js 解析。
使用JSX可以生成React元素。JSX在被編譯後也會轉化成js代碼執行。React中用不用JSX不是一個硬性條件,只是說使用JSX會有更多的好處。
總而言之,能有JSX做的事,用javascript都能做到。
3、舉個栗子(在html文檔中創造一個列表)
3.1 JS
var child1 = React.createElement('li', null, '這是列表下的第一條元素');
var child2 = React.createElement('li', null, '這是列表下的第二條元素');
var new_list = React.createElement('ul', { className: 'my-list' }, child1, child2);
3.2 JSX
const new_list = (
<ul className="my-list">
<li>這是列表下第一條元素</li>
<li>這是列表下第一條元素</li>
</ul>
)
Babel 會把 JSX 轉譯成一個名爲 React.createElement() 函數調用。上述兩種方法實現的效果是一樣的。
4、JSX語法
4.1 JSX 的基本語法規則:
1)遇到 HTML 標籤(以 <
開頭),就用 HTML 規則解析
2)遇到代碼塊(以 {
開頭),就用 JavaScript 規則解析
4.2 JSX 語法示例:
const element = <h1>Hello, world!</h1>;
/* 若一個標籤裏面沒有內容,可以使用 /> 來閉合標籤 */
const element = <img src={user.avatarUrl} />;
4.3 表達式嵌套
1、在JSX中,我們還可以使用表達式
/* 通過 { } 接收參數 name */
const name = 'Reactjs';
const element = <h1>Hello, {name}</h1>;
2、在JSX中,我們可以在大括號內放置任何有效的 JavaScript 表達式。這些表達式可以爲:
(1)變量名
(2)函數定義表達式
(3)屬性訪問表達式
(4)函數調用表達式
(5)算數表達式
(6)關係表達式
(7)邏輯表達式
1、放置算數表達式:
const element = <h1>計算10+5的結果:{10+5}</h1>;
2、放置調用函數:
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = <h1>Hello, {formatName(user)}</h1>;
3、JSX作爲表達式返回
/* 可以在其他 javascript 中返回 JSX 生成的 DOM 對象 */
function getGreeting(user) {
if (user) {
return <h1>Hello, {formatName(user)}!</h1>;
}
return <h1>Hello, Stranger.</h1>;
}
4.4 命名規則
因爲 JSX 語法上更接近 JavaScript 而不是 HTML,所以 React DOM 節點使用 camelCase(小駝峯命名)來定義屬性的名稱,而不使用 HTML 屬性名稱的命名約定。
例如,JSX 裏的 class 變成了 className
,而 tabindex 則變爲 tabIndex
。
4.5 JSX 對象
const element = <h1 className="greeting">Hello, world!</h1>;
上述JSX語法生成的對象結構:
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
這些對象被稱爲 “React 元素”。它們描述了你希望在屏幕上看到的內容。React 通過讀取這些對象,然後使用它們來構建 DOM 以及保持隨時更新
二、元素
元素是構成 React 應用的最小磚塊。它描述了你在屏幕上想看到的內容。也就是我們日常瀏覽網頁時看到的網頁上的圖片,文字,表格,列表等等,這些都是由一個或者多個元素組成。
例如:<a>
、<h1>
、<div>
、<span>
、<img>
等
渲染元素也就是畫畫,將定義的元素在網頁中繪製出來,將react渲染成爲一個html DOM
1、ReactDOM
我們在使用react開發網頁時,會下載兩個包,一個是react,一個是react-dom,其中react包是react的核心代碼,react-dom則是React剝離出的涉及DOM操作的部分。
react的核心思想是虛擬DOM,react包含了生成虛擬DOM的函數react.createElement,及Component類。當我們自己封裝組件時,就需要繼承Component類,才能使用生命週期函數等。
react-dom包的核心功能就是把這些虛擬DOM渲染到文檔中變成實際DOM。下面學習 ReactDOM 的 API 函數
1.1 render()
render用於將React渲染的虛擬DOM渲染到瀏覽器DOM,一般在頂層組件使用
(1)語法
render(ReactElement element,DOMElement container,[function callback])
@param:
ReactElement element:待渲染的元素或者組件
DOMElement container:容器節點(已經存在的DOM節點)
[function callback]:回調函數
(2)例子
import ReactDOM from 'react-dom';
/* 渲染組件*/
/* <Example /> 爲自定義組件 */
ReactDOM.render(<Example />, document.getElementById('root'));
/* 渲染元素 */
const element = <h1>Hello, world!</h1>;
ReactDOM.render(element, document.getElementById('root'));
(3)一些注意事項
1)ReactDOM.render()
會控制傳入容器節點裏的內容。當首次調用時,容器節點裏的所有 DOM 元素都會被替換,後續的調用則會使用 React 的 DOM 差分算法(DOM diffing algorithm)進行高效的更新。
2)ReactDOM.render()
不會修改容器節點(只會修改容器的子節點)。可以在不覆蓋現有子節點的情況下,將組件插入已有的 DOM 節點中。
1.2 findDOMNode()
當我們通過render()方法將組件渲染成DOM以後,避免不了獲取該組件的操作,通過findDOMNode()方法可以返回已經完成渲染的組件對應的DOM節點。
(1)語法
ReactDOM.findDOMNode(component)
(2)注意事項
1)findDOMNode 是一個訪問底層 DOM 節點的應急方案。在大多數情況下,不推薦使用該方法,因爲它會破壞組件的抽象結構
2)大多數情況下,你可以綁定一個 ref 到 DOM 節點上,可以完全避免使用 findDOMNode。
3)findDOMNode 只在已掛載的組件上可用(即,已經放置在 DOM 中的組件)。如果你嘗試調用未掛載的組件(例如在一個還未創建的組件上調用 render() 中的 findDOMNode())將會引發異常。
4)findDOMNode 不能用於函數組件。
1.3 unmountComponentAtNode()
從 DOM 中卸載組件,會將其事件處理器(event handlers)和 state 一併清除。如果指定容器上沒有對應已掛載的組件,這個函數什麼也不會做。如果組件被移除將會返回 true,如果沒有組件可被移除將會返回 false。
(1)語法
ReactDOM.unmountComponentAtNode(container)
2、更新元素
React DOM 會將元素和它的子元素與它們之前的狀態進行比較,並只會進行必要的更新來使 DOM 達到預期的狀態。
計時器例子:
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(element, document.getElementById('root'));
}
setInterval(tick, 1000);
對於上述例子,render每次渲染的時候,都只對h2
進行更新,對於沒有改變的元素,render不會對其進行重新渲染。這裏面涉及到一個react的差分算法
。
三、組件
首先需要區分組件跟元素的概念,組件是由元素構成的。元素數據結構是普通對象,而組件數據結構是類或純函數。
就拿建造一座大樓來說,
如果說我們最後使用React構建的網頁一座輝煌的高樓。
那麼,元素就是磚塊,組件就是每一間房間,例如廁所組件、臥室組件、廚房組件,這些組件都是一塊一塊磚構成,這一座樓房又是有這些房間組件構成。
1、函數組件
定義組件最簡單的方式就是編寫 JavaScript 函數:
function Hello(props) {
return <h1>Hello, {props.name}</h1>;
}
2、class組件
定義 class 組件,需要繼承 React.Component:
class Hello extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
3、渲染組件
回顧之前的元素,發現到目前爲止,遇到到React元素都是html DOM 標籤,例如
const element = <div />;
const element = <a />;
const element = <img />;
React 元素也可以是用戶自定義的組件:
const element = <Hello name="Lisa" />;
上面定義了一個名叫Hello的組件
function Hello(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Hello name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
1、調用 ReactDOM.render() 函數,並傳入 <Hello name="Sara" /> 作爲參數。
2、React 調用 Hello 組件,並將 {name: 'Lisa'} 作爲 props 傳入。
3、Hello 組件將 <h1>Hello, Lisa</h1> 元素作爲返回值。
4、React DOM 將 DOM 高效地更新爲 <h1>Hello, Lisa</h1>
4、自定義組件規則
組件名稱必須以大寫字母開頭
以小寫字母開頭的元素代表一個 HTML 內置組件,比如 <div>
或者 <span>
會生成相應的字符串 ‘div’ 或者 ‘span’ 傳遞給React.createElement(作爲參數)。大寫字母開頭的元素則對應着在 JavaScript 引入或自定義的組件,如 <Foo />
會編譯爲 React.createElement(Foo)。
import React from 'react';
// 錯誤!組件應該以大寫字母開頭:
function hello(props) {
// 正確!這種 <div> 的使用是合法的,因爲 div 是一個有效的 HTML 標籤
return <div>Hello {props.toWhat}</div>;
}
// 正確!組件以大寫字母開頭了:
function HelloWorld() {
// 錯誤!React 會認爲 <hello /> 是一個 HTML 標籤,因爲它沒有以大寫字母開頭:
return <hello toWhat="World" />;
}
5、混合組件
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
/* 調用自定義的 Welcome 組件*/
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);