零基础入门 React 教程(第二部分)
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
在我上一篇关于从零开始学习 React 的随笔博文中,我开始学习ReactJS.org 的教程。我通过复制粘贴代码构建了我的第一个应用程序……但它居然运行成功了!今天,我希望能理解一些我运行的代码。让我们开始吧。
这部分我大概理解了。` React.Component<Component>` 是一个基础组件类,我们创建了一个ShoppingList继承它的类。我猜想组件必须有一个render()方法,该方法返回一些要渲染的 HTML 元素。这里创建了一个<div>带有 ` <header>`className属性的 `<component>` 元素——这和 HTML 的 `<body>` 属性类似吗class? ——该元素包含一个头部(`<header>` <h1>)和一个无序列表(`<unordered list> <ul>`),其中列出了 Mark 想要收购的所有公司。
this.props.name我猜,`${{}` 访问的是 `${{} props` 的变量this,我猜它指的是该类的实例ShoppingList。它访问的name是 `${{}`,该变量在示例中类似 XML 的标签中定义。如果可以像这样随意定义属性,那么这种语法就非常酷了。但是,如果我们不将 `${}` 传递给 `${}` 会怎样呢name?ShoppingList代码会抛出错误吗?还是会{this.props.name}在应该显示 `${}` 的地方什么都不渲染?
“当我们的数据发生变化时,React 会高效地更新并重新渲染我们的组件。”
原来它是一个响应式编程框架,跟我预想的一样。考虑到它的名字,这也很合理。
“这里的 ShoppingList 是一个React 组件类,或者说React 组件类型。组件接收参数
props(称为属性),并通过render方法返回要显示的视图层次结构。”
我的想法也差不多,但我不太明白“视图层级”是什么意思。教程里说,上面那段看起来很像 HTML 的代码也可以这样写:
React.createElement("div", { className: "shopping-list" },
React.createElement("h1", null, "Shopping List for ", props.name),
React.createElement("ul", null,
React.createElement("li", null, "Instagram"),
React.createElement("li", null, "WhatsApp"),
React.createElement("li", null, "Oculus")
)
);
这让我想起了JavaFX 使用 FXML 和不使用 FXML的区别。使用FXML构建 Java GUI 时,标记更像 XML。而不用 FXML,它看起来更像上面那段代码,其中函数和属性都是通过点.运算符 () 来访问的。
教程中说“ API 参考文档createElement中有更详细的描述”,所以我点击了那个链接,希望能找到一些注释完善的代码:
文档看起来很不错,很容易理解。我猜[props]它是一个属性列表?不过,在上面的代码块中,我们将第二个参数放在了createElement花括号里{className: 'shopping-list'}。但是,当我们把可变参数列表传递[...children]给 `get` 时,它并没有被花括号括起来createElement……我有点困惑。也许有两种类型的列表?一种是列表,另一种是字典(或映射)?
这真是太棒了。这样我们就可以一点一点地用小组件搭建一个应用程序,并在更大的组件中使用这些小组件。下一步是检查我在上一篇文章中复制粘贴的 JavaScript 代码:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
class Square extends React.Component {
render() {
return (
<button className="square">
{/* TODO */}
</button>
);
}
}
class Board extends React.Component {
renderSquare(i) {
return <Square />;
}
render() {
const status = 'Next player: X';
return (
<div>
...
看起来挺容易理解的。正如教程里提到的,我们有一个Square类,还有一个Board类用来渲染井字棋游戏的九个方格。我猜还有一些代码需要我来写。
没错。下一步是填写两处小细节,我们进行一些更改。
renderSquare(i) {
return <Square />;
}
到
renderSquare(i) {
return <Square value={i} />
}
和变化
{/* TO-DO */}
到
{this.props.value}
这段代码传递了要在按钮上渲染的正方形的“值”。我修改了这段代码并npm start再次运行。渲染仍然需要很长时间。但它确实有效……
……也算是个好消息。
恭喜!您刚刚成功地将一个属性从父组件 Board 传递给了子组件 Square。在 React 应用中,信息就是通过传递属性(props)从父组件传递到子组件的。
接下来,我们要在 ` in`中添加一个onClick方法,该方法会打开一个 JavaScript窗口。几年前我接触过 JavaScript,以前也遇到过类似的情况,所以对我来说并不难。buttonSquarealert()
接下来,我们将该onClick函数替换为“箭头函数”(在 JavaScript 中它们似乎就是这么叫的)。我认为大多数其他编程语言都称它们为“lambda 函数”:
onClick={function() { alert('click'); }}
……变成……
onClick={() => alert('click')}
这样可以省去一些打字的步骤。教程中特别提到我们需要传递一个函数。onClick如果我们只写……
onClick={alert('click')}
那么每次组件重新渲染时都会触发警告。这显然不是我们想要的结果。
接下来,我们给类添加state一个Square属性,让它能够“记住”是否被点击过。这类似于大多数面向对象编程语言中的实例变量/成员变量。看起来我们可以在类定义中的函数state里设置 React 对象的属性:constructor
class Square extends React.Component {
constructor(props) {
super(props);
this.state = {
value: null
};
}
}
这里有两点:
- 这个
Square类显然调用了父类的构造函数(React.Component)super(),并将传递props给父类构造函数。 - 教程中“”后面实际上有个逗号
null,我猜这是个拼写错误。
在 JavaScript 类中,定义子类的构造函数时必须始终调用 `__init__`
super。所有带有 `__init__` 的 React 组件类都constructor应该以 `__init__` 调用开头super(props)。
看起来super(props)在任何子类中都是必需的constructor。我想知道它是否必须像 Java 那样,是构造函数的第一行……?上面的摘录对此有点含糊不清。
然后我们通过改变按钮的onClick状态button来改变按钮的属性setState(),这似乎很容易。
onClick={() => alert('click')}
变化
onClick={() => this.setState({value: 'X'})}
当你
setState在组件中调用某个函数时,React 会自动更新该组件内部的子组件。
这听起来像是响应式依赖。如果一个对象更新,而其他对象依赖于它,那么这些依赖对象也会被更新。
最后一步是安装React Developer Tools Chrome 扩展程序,这样我就可以在浏览器中检查我的 React 代码了:
好的!
嗯,我确实开始理解 React 的工作原理了。看到像类、构造函数和 lambda 函数这些熟悉的东西,让我更有信心能很快上手。目前为止,我基本上只是做了onClick些功能强大的网页,所以我希望这个框架还能让我做更多的事情。我期待着做出一些很酷的交互式网页!




