一、Instances概念:
基于传统的面向对象的UI编程,任何一个对象,都需要在使用之前先创建(new),使用完之后需要销毁(delete);无论是创建还是销毁,都必需谨慎的手工维护,如下伪代码(pseudocode):
class Form extends TraditionalObjectOrientedView {
render() {
// Read some data passed to the view
const { isSubmitted, buttonText } = this.attrs;
if (!isSubmitted && !this.button) {
// Form is not yet submitted. Create the button!
this.button = new Button({
children: buttonText,
color: 'blue'
});
this.el.appendChild(this.button.el);
}
if (this.button) {
// The button is visible. Update its text!
this.button.attrs.children = buttonText;
this.button.render();
}
if (isSubmitted && this.button) {
// Form was submitted. Destroy the button!
this.el.removeChild(this.button.el);
this.button.destroy();
}
if (isSubmitted && !this.message) {
// Form was submitted. Show the success message!
this.message = new Message({ text: 'Success!' });
this.el.appendChild(this.message.el);
}
}
}
上面代码中:
- Button和Message在创建(new)时,会将instance保存起来,再之后需要使用的时候再操作;
- 同时,我们还注意到,每个对象的实例(instance)都与DOM保持的关联;
传统开发中,每个对象都要如此维护,既费时又费力,代码也几何膨胀,将来难以维护。
二、Elements
Elements(元素)的定义:
An element is a plain object describing a component instance or DOM node and its desired properties. It contains only information about the component type (for example, a Button), its properties (for example, its color), and any child elements inside it.
元素是一个纯对象,描述一个组件实例,或一个DOM的节点和它的属性。元素只包含了组件的类型和它的属性,以及它内部的子元素。
Elements并不是一个真正的实例,相反地,它只是告诉React你能在屏幕上看到你所希望看到的一种方式。你不能直接调用元素的任何方法,因为它是不可变的对象且只有两个成员:type: (string | ReactClass) 和 props: Object。
例如一个DOM Elements如下:
{
type: 'button',
props: {
className: 'button button-blue',
children: {
type: 'b',
props: {
children: 'OK!'
}
}
}
}
该元素作为一个纯对象显示在HTML中如下:
<button class='button button-blue'>
<b>
OK!
</b>
</button>
该例子显示了Elements是如何嵌套的!如果我们想要创建一个Elements Tree,我们只需要指定一个或多个子元素被包含在props的children中即可。
重点:
- 无论是父元素还是子元素,都只是一些描述而不是真实的实例,它们并不会与屏幕上的内容有直接关联!
- React Elements很容易遍历,并不需要额外的解析,它比真实的DOM Elements要轻的多,因为它们只是对象而已!
三、Components(Elements)
上节提到过,组件也是元素!一个元素的类型也可以是function或class。
{
type: Button,
props: {
color: 'blue',
children: 'OK!'
}
}
这是React的核心思想!
An element describing a component is also an element, just like an element describing the DOM node. They can be nested and mixed with each other.
一个元素描述一个组件,同时它还是一个元素,就如一个元素描述DOM节点一样。组件可以被其它组件嵌套和混合。
该功能可以让你定义一个DangerButton组件作为一个Button而不需要担心会被渲染为DOM <button>,还是 <div>,或者其它。
// 定义DangerButton组件
const DangerButton = ({ children }) => ({
type: Button,
props: {
color: 'red',
children: children
}
});
混合到另一个Elements Tree中如下:
const DeleteAccount = () => ({
type: 'div',
props: {
children: [{
type: 'p',
props: {
children: 'Are you sure?'
}
}, {
type: DangerButton,
props: {
children: 'Yep'
}
}, {
type: Button,
props: {
color: 'blue',
children: 'Cancel'
}
}]
});
直观的JSX如下:
const DeleteAccount = () => (
<div>
<p>Are you sure?</p>
<DangerButton>Yep</DangerButton>
<Button color='blue'>Cancel</Button>
</div>
);
这使得这些组件能够解耦(decoupled),且能够表示它们之间的关系是 is-a 和 has-a :
- Button is a DOM <button> with specific properties.
- DangerButton is a Button with specific properties.
- DeleteAccount contains a Button and a DangerButton inside a <div>.
四、Components 封装了 Element Trees
当React发现了一个元素它的类型是 function 或 class,它知道去调用这个组件该如果渲染其元素,以及给定的props。
// Button组件元素如下:
{
type: Button,
props: {
color: 'blue',
children: 'OK!'
}
}
当React看到是一个Button组件时,将调用Button该如何渲染,Button组件将返回如下元素:
{
type: 'button',
props: {
className: 'button button-blue',
children: {
type: 'b',
props: {
children: 'OK!'
}
}
}
}
React会不断重复这个过程,直到React完全知道每个组件的DOM tag。
我们回到最开始的例子,改写它,如下:
const Form = ({ isSubmitted, buttonText }) => {
if (isSubmitted) {
// Form submitted! Return a message element.
return {
type: Message,
props: {
text: 'Success!'
}
};
}
// Form is still visible! Return a button element.
return {
type: Button,
props: {
children: buttonText,
color: 'blue'
}
};
};
The returned element tree can contain both elements describing DOM nodes, and elements describing other components. This lets you compose independent parts of UI without relying on their internal DOM structure.
返回的元素树可以同时包含描述DOM节点的元素,以及描述其它组件的元素。这使得你能够组合独立的UI而不需要依赖内部DOM结构。We let React create, update, and destroy instances. We describe them with elements we return from the components, and React takes care of managing the instances.
我们让React来创建、更新和销毁实例。我们只描述那些从组件中返回的元素,React会管理它们。
五、Components Can Be Classes or Functions
最开始的例子,改成组件(用class或Function)如下:
// 1) As a function of props
const Button = ({ children, color }) => ({
type: 'button',
props: {
className: 'button button-' + color,
children: {
type: 'b',
props: {
children: children
}
}
}
});
// 2) Using the React.createClass() factory
const Button = React.createClass({
render() {
const { children, color } = this.props;
return {
type: 'button',
props: {
className: 'button button-' + color,
children: {
type: 'b',
props: {
children: children
}
}
}
};
}
});
// 3) As an ES6 class descending from React.Component
class Button extends React.Component {
render() {
const { children, color } = this.props;
return {
type: 'button',
props: {
className: 'button button-' + color,
children: {
type: 'b',
props: {
children: children
}
}
}
};
}
}
组件用class来定义,比用Function来定义,更好一些,因为,class可以存储一些本地状态以及执行一些用户逻辑。如果没有什么逻辑,我们建议直接使用Function来简单返回元素树就行。
【注】这里我们推荐组件实现如下:
- 如果组件没有state,也没有其它执行逻辑,则用Function来定义;
- 如果组件有state,或者有用户逻辑,则用class来定义;
However, whether functions or classes, fundamentally they are all components to React. They take the props as their input, and return the elements as their output.
但是,无论用Functions还是classes,它们都是React组件的基础。它们将props作为输入,返回的元素作为输出。
六、Top-Down Reconciliation(自顶向下的调和)
一个简单的例子下:
ReactDOM.render({
type: Form,
props: {
isSubmitted: false,
buttonText: 'OK!'
}
}, document.getElementById('root'));
React将问Form组件,给定props,它将返回什么元素树。React将不断的重复这个过程直到它能够理解你的组件树中最简单的原语。
// React: You told me this...
{
type: Form,
props: {
isSubmitted: false,
buttonText: 'OK!'
}
}
// React: ...And Form told me this...
{
type: Button,
props: {
children: 'OK!',
color: 'blue'
}
}
// React: ...and Button told me this! I guess I'm done.
{
type: 'button',
props: {
className: 'button button-blue',
children: {
type: 'b',
props: {
children: 'OK!'
}
}
}
}
这个处理过程React称作调和,这个过程的起始为当你调用ReactDOM.render()或setState(),在调和结束时,React知道DOM树的结果,以及适用于一组需要更新DOM节点所需的最小的如react-dom或react-native的渲染器。
这个不断重复的过程也是React容易优化的原因。如果组件树的某个部分变的很大导致React无法有效的访问,你可以告诉React跳过这个重复,并且如果相关的props没有改变,则只比较树的确定部分。如果props是不可变的,那么React将非常快速的计算出props是否发生改变,因此,React与不可变在一起工作将更好,它能够花费最小的努力而提供高效的优化(事倍功半)。
你可能注意到,这里讲了很多组件和元素,但并没怎么讲实例。事实是,在React中,实例比起面向对象的UI框架将不那么重要(前面提到了,React来负责实例)。
网友评论