Components
Components
注意
本文档特意编写在靠近 ReactJS/Components and Props 文章的地方,以突出与 ReactJS 的异同。
Components and Props
Conceptually, components are script functions. They accept arbitrary inputs (called “props”) and return virtual elements describing what should appear on the screen.
Function and Class Components
定义组件的最简单方法是编写脚本函数:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
此函数是有效的 Reactor 组件,因为它接受带有数据的单个“props”对象参数并返回一个虚拟元素。我们称这些组件为“函数组件”,因为它们实际上是脚本函数。
您还可以使用类来定义组件:
class Welcome extends Element {
this(props) {
this.props = props;
}
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
这两个组件在使用时将完全相同。
基于类的组件具有一些附加功能,我们将在下一节中讨论这些功能。在此之前,我们将使用函数组件来简洁。
注意组件名称(函数名称或基于类的名称)应以大写字母开头。
Component-functions and component constructors signatures
组件函数和构造函数的完整声明可能如下所示:
function FunctionComponent(props, kids [,parent]) {}
哪里:
道具是传递的属性;
孩子就是孩子,内容VNodes;
parent 是组件将出现在其中的父 DOM 元素。
此环境变量可以
null
是全新元素的对象,也可以是现有元素的对象instanceof Element
。
示例,此声明:
<FunctionComponent mode="start">
<div>bar</div>
</FunctionComponent>
将使用以下参数调用 FunctionComponent():
道具-
{ mode: "start" }
孩子-
[ <div>bar</div> ]
类组件的构造函数遵循相同的约定:
class ClassComponent extends Element {
constructor(props,kids,parent) {...}
}
父参数接收 DOM 元素 - 将来或现有的容器 DOM 元素。
Rendering a Component
以前,我们只遇到过表示 DOM 标签的 Reactor 虚拟元素:
const velement = <div />;
但是,元素也可以表示用户定义的组件:
const velement = <Welcome name="John" />;
当脚本编译器看到表示用户定义组件的元素时,它会将其属性作为单个对象传递给该组件。我们称这个对象为“道具”。
例如,以下代码在页面上呈现“Hello, Ivan!”:
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>;
}
const velement = <Welcome name="Ivan" />;
document.body.content(velement);
让我们回顾一下上面示例中发生的情况:
我们用
<Welcome name="Ivan" />
元素调用element.content(velement)
。Sciter 运行时将
Welcome
组件 with{name: "Ivan"}
作为 props 对象调用。我们的
Welcome
组件返回一个<h1>Hello, Ivan</h1>
虚拟元素作为结果。element.content()
函数使用该虚拟元素定义插入 DOM 元素<h1>Hello, Ivan!</h1>
。
Composing Components
组件可以在其输出中引用其他组件。这使我们能够对任何细节级别使用相同的组件抽象。一个按钮,一个窗体,一个对话框,所有这些通常都可以表示为组件。
例如,我们可以创建一个 Welcome
渲染多次的 App
组件:
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>;
}
function App() {
return <body>
<Welcome name="Ivan" />
<Welcome name="Olga" />
<Welcome name="Andrew" />
</body>;
}
document.body.patch( <App /> );
Extracting Components
不要害怕将组件拆分为更小的组件。
例如,请考虑以下 Comment
组件:
function Comment(props) {
return
<div .comment>
<div .userinfo>
<img .avatar src={props.author.avatarUrl} alt={props.author.name} />
<div .userinfo-name>{props.author.name}</div>
</div>
<div .comment-text>{props.text}</div>
<div .comment-date>{formatDate(props.date)}</div>
</div>;
}
它接受 author
(对象)、 text
(字符串)和 date
(日期)作为道具,并描述聊天实现中的注释。
由于所有嵌套,此组件的更改和维护可能很棘手,并且也很难重用其各个部分。
让我们从中提取一些组件。首先,我们将提取 Avatar
:
function Avatar(props) {
return <img.avatar
src={props.user.avatarUrl}
alt={props.user.name}/>;
}
接下来,我们将提取一个 UserInfo
组件,该组件在用户名旁边呈现: Avatar
function UserInfo(props) {
return <div.userinfo>
<Avatar user={props.user} />
<div.userinfo-name>{props.user.name}</div>
</div>;
}
最后简化 Comment
为由上述内容组成:
function Comment(props) {
return <div.comment>
<UserInfo user={props.author} />
<div.comment-text>{props.text}</div>
<div.comment-date>{formatDate(props.date)}</div>
</div>;
}
提取组件乍一看似乎是一项繁琐的工作,但在大型应用中,拥有可重用组件的调色板是值得的。
一个好的经验法则是,如果 UI 的某个部分被多次使用( Button
, Panel
, Avatar
),或者它本身足够复杂 ( App
, FeedStory
, Comment
),那么它就是一个可重用的组件。