createElement
createElement
允许你创建一個 React 元素。它可以作為 JSX 的替代方案。
const element = createElement(type, props, ...children)
參考
createElement(type, props, ...children)
調用 createElement
來創建一個 React 元素,它有 type
, props
, and children
三個參數。
import { createElement } from 'react';
function Greeting({ name }) {
return createElement(
'h1',
{ className: 'greeting' },
'你好'
);
}
參數
-
type
:type
參數必須是一個有效的 React 組件類型,例如一個字串標籤名(如'div'
或'span'
),或一個 React 組件(一個函數式組件、一個類式組件,或者是一個特殊的組件如Fragment
)。 -
props
:props
參數必須是一個物件或null
。如果你傳入null
,它會被當作一個空物件。創建的 React 元素的props
與這個參數相同。注意,props
物件中的ref
和key
比較特殊,它們 不會 作為element.props.ref
和element.props.key
出現在創建的元素element
上,而是作為element.ref
和element.key
出現。 -
可選
...children
:零個或多個子節點。它們可以是任何 React 節點,包括 React 元素、字串、數字、portal、空節點(null
、undefined
、true
和false
),以及 React 節點陣列。
返回值
createElement
返回一個 React 元素,它有這些屬性:
type
: 你傳入的type
。props
: 你傳入的props
,不包括ref
和key
。如果type
是一個組件,且帶有過時的type.defaultProps
屬性,那麼props
中任何缺失或未定義的欄位都會採用type.defaultProps
中的值。ref
: 你傳入的ref
。如果缺失則為null
。key
: 你傳入的key
,會被強制轉換為字串。如果缺失則為null
。
通常你會在你組件的最後返回這個元素,或者把它作為另一個元素的子元素。雖然你可以讀取元素的屬性,但你最好把創建的元素作為黑盒,只用於渲染。
注意事項
-
你必須將 React 元素和它們的 props 視為不可變的,在創建後永遠不要改變它們的內容。在開發環境中,React 會淺層凍結返回的元素及其
props
屬性,以確保如此。 -
當你使用 JSX 時,你必須以大寫字母開頭來渲染你的自定義組件。換句話說,
<Something />
等價於createElement(Something)
,但<something />
(小寫)等價於createElement('something')
(注意它是一個字串,它會被當作內建的 HTML 標籤)。 -
你應該僅在所有子元素都是靜態可知的情況下,才將它們依次傳遞給
createElement
的可選參數,比如createElement('h1', {}, child1, child2, child3)
。如果你的子元素不固定,則把它們放到數組中作為第三個參數傳遞,例如createElement('ul', {}, listItems)
,以此確保 React 可以在動態列表的場景下警告你缺少key
。靜態列表的場景不需要這麼做,因為它們不會重新排序。
用法
不使用 JSX 創建元素
如果你不喜歡 JSX 或者無法在你的專案中使用它,你可以使用 createElement
作為替代方案。
要想不使用 JSX 創建一個元素,你可以調用 createElement
並傳入 type、props 和 children:
import { createElement } from 'react';
function Greeting({ name }) {
return createElement(
'h1',
{ className: 'greeting' },
'你好',
createElement('i', null, name),
'。歡迎!'
);
}
children 是可選的,你可以傳入任意數量的子元素(上面的例子中有三個)。這段程式碼會顯示一個帶有問候語的 <h1>
標題。為了對比,這是使用 JSX 的版本:
function Greeting({ name }) {
return (
<h1 className="greeting">
你好<i>{name}</i>,歡迎!
</h1>
);
}
要想渲染你自己的 React 組件,則傳入一個函數(比如 Greeting
)作為 type ,而不是一個字串(比如 'h1'
):
export default function App() {
return createElement(Greeting, { name: '泰勒' });
}
如果使用 JSX,它看起來像這樣:
export default function App() {
return <Greeting name="泰勒" />;
}
這裡是一個完整的使用 createElement
的示例:
import { createElement } from 'react'; function Greeting({ name }) { return createElement( 'h1', { className: 'greeting' }, '你好', createElement('i', null, name), ',歡迎!' ); } export default function App() { return createElement( Greeting, { name: '泰勒' } ); }
這裡是相同的示例,但使用的是 JSX:
function Greeting({ name }) { return ( <h1 className="greeting"> 你好<i>{name}</i>,歡迎! </h1> ); } export default function App() { return <Greeting name="泰勒" />; }
兩種編碼風格都沒問題,你可以在專案中使用任何一個你喜歡的風格。相比於 createElement
,使用 JSX 的主要好處是很容易看出哪個閉合標籤對應哪個開放標籤。
Deep Dive
元素是用來描述一部分使用者介面的輕量級結構。例如,<Greeting name="泰勒" />
和 createElement(Greeting, { name: '泰勒' })
都會生成一個這樣的物件:
// 極度簡化的樣子
{
type: Greeting,
props: {
name: '泰勒'
},
key: null,
ref: null,
}
請注意,創建這個物件並不會渲染 Greeting
組件或者創建任何 DOM 元素。
React 元素更像是一個描述或指令,它告訴 React 之後該如何渲染 Greeting
組件。你從 App
組件中返回了這個物件,就是告訴了 React 接下來該做什麼。
創建元素非常高效,因此你不需要試圖優化或避免它。