在 React 的術(shù)語中,有五個(gè)核心類型,區(qū)分它們是很重要的:
React 中最主要的類型就是 ReactElement
。它有四個(gè)屬性:type
,props
,key
和 ref
。它沒有方法,并且原型上什么都沒有。
可以通過 React.createElement
創(chuàng)建該類型的一個(gè)實(shí)例。
var root = React.createElement('div');
為了渲染一個(gè)新的樹形結(jié)構(gòu)到 DOM 中,你創(chuàng)建若干個(gè) ReactElement
,然后傳給 React.render
作為第一個(gè)參數(shù),同時(shí)將第二個(gè)參數(shù)設(shè)為一個(gè)正規(guī)的 DOM 元素
(HTMLElement
或者 SVGElement
)。不要混淆 ReactElement
實(shí)例和 DOM 元素
實(shí)例。一個(gè) ReactElement
實(shí)例是一個(gè)輕量的,無狀態(tài)的,不可變的,虛擬的 DOM 元素
的表示。是一個(gè)虛擬 DOM。
React.render(root, document.body);
要添加屬性到 DOM 元素,把屬性對(duì)象作為第二個(gè)參數(shù)傳入 React.render
,把子級(jí)作為第三個(gè)參數(shù)傳給 React.render
。
var child = React.createElement('li', null, 'Text Content');
var root = React.createElement('ul', { className: 'my-list' }, child);
React.render(root, document.body);
如果使用 React JSX 語法,這些 ReactElement
實(shí)例自動(dòng)創(chuàng)建。所以,如下代碼是等價(jià)的:
var root = <ul className="my-list">
<li>Text Content</li>
</ul>;
React.render(root, document.body);
工廠
一個(gè) ReactElement
工廠就是一個(gè)簡(jiǎn)單的函數(shù),該函數(shù)生成一個(gè)帶有特殊 type
屬性的 ReactElement
。React 有一個(gè)內(nèi)置的輔助方法用于創(chuàng)建工廠函數(shù)。事實(shí)上該方法就是這樣的:
function createFactory(type){
return React.createElement.bind(null, type);
}
該函數(shù)能創(chuàng)建一個(gè)方便的短函數(shù),而不是總調(diào)用 React.createElement('div')
。
var div = React.createFactory('div');
var root = div({ className: 'my-div' });
React.render(root, document.body);
React 已經(jīng)內(nèi)置了常用 HTML 標(biāo)簽的工廠函數(shù):
var root = React.DOM.ul({ className: 'my-list' },
React.DOM.li(null, 'Text Content')
);
如果使用 JSX 語法,就不需要工廠函數(shù)了。JSX 已經(jīng)提供了一種方便的短函數(shù)來創(chuàng)建 ReactElement
實(shí)例。
一個(gè) ReactNode
可以是:
ReactElement
string
(又名 ReactText
)number
(又名 ReactText
)ReactNode
實(shí)例數(shù)組 (又名 ReactFragment
)這些被用作其它 ReactElement
實(shí)例的屬性,用于表示子級(jí)。實(shí)際上它們創(chuàng)建了一個(gè) ReactElement
實(shí)例樹。
(These are used as properties of other ReactElement
s to represent children. Effectively they create a tree of ReactElement
s.)
在使用 React 開發(fā)中,可以僅使用 ReactElement
實(shí)例,但是,要充分利用 React,就要使用 ReactComponent
來封裝狀態(tài)化的組件。
一個(gè) ReactComponent
類就是一個(gè)簡(jiǎn)單的 JavaScript 類(或者說是“構(gòu)造函數(shù)”)。
var MyComponent = React.createClass({
render: function() {
...
}
});
當(dāng)該構(gòu)造函數(shù)調(diào)用的時(shí)候,應(yīng)該會(huì)返回一個(gè)對(duì)象,該對(duì)象至少帶有一個(gè) render
方法。該對(duì)象指向一個(gè) ReactComponent
實(shí)例。
var component = new MyComponent(props); // never do this
除非為了測(cè)試,正常情況下不要自己調(diào)用該構(gòu)造函數(shù)。React 幫你調(diào)用這個(gè)函數(shù)。
相反,把 ReactComponent
類傳給 createElement
,就會(huì)得到一個(gè) ReactElement
實(shí)例。
var element = React.createElement(MyComponent);
或者使用 JSX:
var element = <MyComponent />;
當(dāng)該實(shí)例傳給 React.render
的時(shí)候,React 將會(huì)調(diào)用構(gòu)造函數(shù),然后創(chuàng)建并返回一個(gè) ReactComponent
。
var component = React.render(element, document.body);
如果一直用相同的 ReactElement
類型和相同的 DOM 元素
容器調(diào)用 React.render
,將會(huì)總是返回相同的實(shí)例。該實(shí)例是狀態(tài)化的。
var componentA = React.render(<MyComponent />, document.body);
var componentB = React.render(<MyComponent />, document.body);
componentA === componentB; // true
這就是為什么不應(yīng)該創(chuàng)建你自己的實(shí)例。相反,在創(chuàng)建之前,ReactElement
是一個(gè)虛擬的 ReactComponent
。新舊 ReactElement
可以比對(duì),從而決定是創(chuàng)建一個(gè)新的 ReactComponent
實(shí)例還是重用已有的實(shí)例。
ReactComponent
的 render
方法應(yīng)該返回另一個(gè) ReactElement
,這就允許組件被組裝。
(The render
method of a ReactComponent
is expected to return another ReactElement
. This allows these components to be composed. Ultimately the render resolves into ReactElement
with a string
tag which instantiates a DOM Element
instance and inserts it into the document.)
入口點(diǎn)(Entry Point)
React.render = (ReactElement, HTMLElement | SVGElement) => ReactComponent;
節(jié)點(diǎn)和元素(Nodes and Elements)
type ReactNode = ReactElement | ReactFragment | ReactText;
type ReactElement = ReactComponentElement | ReactDOMElement;
type ReactDOMElement = {
type : string,
props : {
children : ReactNodeList,
className : string,
etc.
},
key : string | boolean | number | null,
ref : string | null
};
type ReactComponentElement<TProps> = {
type : ReactClass<TProps>,
props : TProps,
key : string | boolean | number | null,
ref : string | null
};
type ReactFragment = Array<ReactNode | ReactEmpty>;
type ReactNodeList = ReactNode | ReactEmpty;
type ReactText = string | number;
type ReactEmpty = null | undefined | boolean;
類和組件(Classes and Components)
type ReactClass<TProps> = (TProps) => ReactComponent<TProps>;
type ReactComponent<TProps> = {
props : TProps,
render : () => ReactElement
};