React Javascript 库入门

已发表: 2022-02-16

如果您在 WordPress 世界中度过任何时间,您可能会遇到 Zac Gordon。 Zac 是一位热情而迷人的老师,专注于 WordPress 中的 Javascript。 他从 Matt Mullenweg 那里借用了“Learn Javascript Deeply”这句话,并把它变成了他的个人口号。

在过去的几年里,Zac 制作了视频课程、在线会议、现场演讲和播客,专注于教您如何在 WordPress 中使用 Javascript。

我很高兴地说我们正在与 Zac 合作写一本书,“React Explained”。 React 是 WordPress 团队为新的 Gutenberg 编辑器选择的库。 他们并不孤单——Drupal 和 Magento 都选择了 React。

Zac 在 Twitter 上的 @zgordon 上实时发布他的写作进度。 您还可以在 OSTraining 播客上听到 Zac 谈论 React。

在这本书的摘录中,Zac 为您提供了 React 和一些关键概念的高级概述。


什么是反应?

开箱即用,React 是一个用于构建用户界面的库。

尽管 React 是一个 JavaScript 库,但 React 构建的接口是不可知的。

存在几个 React 配套库以使您构建的界面在浏览器、服务器、本机应用程序甚至 360 和 VR 环境中工作。 在本书中,我们专注于使用 ReactDOM,该库管理将我们使用 React 构建的接口添加到客户端网站和应用程序。 ReactDomServer、ReactNative 和 React360 也是您可能想要探索以在其他环境中使用 React 接口的库。

除了为构建接口提供帮助函数外,React 的架构还允许您处理与接口的交互,无论这涉及事件处理、api 调用、状态管理、接口更新还是更复杂的交互。

React 没有提供像一些 JavaScript 框架那么多的辅助函数。 这在很大程度上是我们将 React 称为库而不是框架的原因。 在使用 React 时,你仍然需要编写大量的原生 JavaScript。


React 组件架构解释

组件是一段独立的、可重用的代码(通过函数或类创建)。

React 使用组件架构来构建用户界面和组织代码。 一个简单的 React 应用程序的主文件可能看起来像这样。

 // 导入 React 和其他组件
从“反应”导入反应;
从'react-dom'导入{渲染};
从'./Header'导入标题;
从'./MainContent'导入MainContent;
从'./Footer'导入页脚;

函数应用程序(){
  返回 (
    <div className="app">
      <标题/>
      <主要内容 />
      <页脚/>
    </div>
 );
}

ReactDOM.render( <App />, document.getElementById("root"));

我们可以在这里看到一些正在使用的组件。 <Header />、<MainContent /> 和 <Footer /> 都是组件。 App() 函数也是一个组件,我们可以在此示例的最后一行看到如何使用 ReactDOM 库和 ReactDOM.render() 方法来管理将我们构建的 UI 添加到网页中。

如果我们深入了解 <Header />、<MainContent /> 和 <Footer /> 组件,我们可能会看到更多组件的使用以及看起来像 HTML 标记的内容。

 从“反应”导入反应;
从“../Ad”导入广告;
从“../assets/logo.svg”导入徽标;

导出默认函数 Header() {
返回 (
<header className="app-header">
<广告 />
<img src={logo} className="app-logo" alt="logo" />
<h1 className="app-title">网站名称</h1>
</标题>
);
}

在上面的这个 <Header /> 组件中,我们可以看到我们正在引入另一个名为 <Ad /> 的组件。 大多数 React 应用程序包含多层组件嵌套,就像我们在 <App />、<Header /> 和 <Ad /> 中看到的那样。

我们还在 React 代码中看到了 HTML 元素的使用。 这要归功于一个名为 JSX 的库,它允许您直接在 JavaScript 中编写“HTML 标记”。 由于我们使用 React 创建用户界面,并且 Web 上的用户界面涉及 HTML 标记,因此我们会在 UI 组件中看到类似 HTML 的元素。 我们将在本书中深入探讨 JSX。

如果我们查看使用 React 360(React 的 VR 库)构建的简单 React 应用程序的一些代码,我们调用的实际组件会有所不同,但组件架构仍然存在。

 从“反应”导入反应;
进口 {
  文本,
  看法,
  虚拟按钮,
} 来自'react-360';

类幻灯片扩展 React.Component {
  // 为简洁起见删除代码
  返回 (
    <查看样式={styles.wrapper}>
      <查看样式={styles.controls}>
        <VrButton onClick={this.prevPhoto}>
          <Text>{'上一个'}</Text>
        </VrButton>
        <VrButton onClick={this.nextPhoto}>
         <Text>{'下一个'}</Text>
        </VrButton>
      <查看>
        <Text style={styles.title}>{current.title}</Text>
      </查看>
    </查看>
  );
}

上面的代码创建了几层 360 度视图,并覆盖了一些按钮和文本。 虽然实际的代码可能没有完全的意义,但应该清楚的是我们有几个嵌套的组件代表视图、按钮和文本。

这是一个很好的例子,因为你可以通过传递不同的参数或 React 所谓的 props 来了解相同的组件是如何以不同的方式重用的。 了解数据如何通过 React 组件对于了解使用 React 构建的典型组件架构非常重要。


React 数据流解释

React 遵循在组件层次结构中的最高点获取和设置数据的约定,以便数据以单向方向向下通过应用程序。让我们看一下这个例子,想象一下我们需要的一些数据类型对于各种组件。

 函数应用程序(){
  返回(
    <React.Fragment>
      <标题/>
      <内容/>
      <侧边栏 />
      <页脚/>
    </React.Fragment>
  );
}

<Header /> 和 <Footer /> 可能需要类似站点名称的名称。 特定页面的主要内容需要传递给 <Content />。 一些额外的小部件数据可能需要转到 <Sidebar />。

 函数应用程序(){
  常量 siteTitle = getSiteTitle();
  常量小部件 = getWidgets();
  常量 mainContent = getPageContent();
  返回(
    <React.Fragment>
      <标题站点标题={站点标题} />
      <内容 mainContent={mainContent} />
      <Sidebar widgets={widgets} />
      <页脚站点标题={站点标题} />
    </React.Fragment>
  );
}

这种组成属性名称并为其分配值的约定是我们将数据传递到组件的方式。

现在 <Header /> 和 <Footer /> 可以访问 siteTitle,<Content /> 可以访问 mainContent,<Sidebar /> 可以访问它需要的小部件。

一个重要的注意事项是,这种将数据传递到组件的模式只传递了一层数据。 <Header /> 内的组件不会自动访问 siteTitle。

 功能标题(道具){
  返回(
    <标题>
      <p>我们可以在这里看到 {props.siteTitle}。</p>
      <PageHeader siteTitle={props.siteTitle} />
      <PageSubHeader />
    </标题>
  );
}

您可以在此处看到,在 <Header /> 内部,我们可以调用 props.siteTitle 并可以访问我们传递给它的值。 但是,如果我们想在 <PageHeader /> 组件中访问 siteTitle,我们也必须手动向下传递该信息。

当一个组件接收一个值作为 props 时,它不应该修改它。 道具应该作为不可变数据通过组件树。 这可以确保任何引用 prop 的组件都引用与其子组件的父级相同的值。

prop 的值只能在最初设置 prop 值并开始通过组件树向下传递的组件中更改。 在我们上面的示例代码中,<App /> 组件可以更改 siteTitle 的值,但 <Header /> 或 <PageHeader /> 组件不应该。

要了解 React 应用程序中动态数据如何更新的流程,需要讨论状态以及如何将事件处理程序作为 props 传递。


React 组件状态解释

正如我们所了解的,数据通过组件作为道具不变地向下流动。 数据设置在树中的最高组件,所有子组件都需要作为道具传递信息。

在某些情况下,此数据只接收一次,无需更改。 在许多情况下,尽管数据必须保持动态,并且能够在任何给定时间更新,并且该更新反映在所有子组件中。

为了跟踪 React 中变化的数据,我们有一个 React 状态对象和一组帮助函数来更新状态值。

这是一个会自我更新的计数器的示例。 计数器的值是该组件中的动态值,因此可以很好地说明何时依赖状态。 请注意,要使组件具有状态,我们必须使用 JavaScript 类而不是函数。

 类计数器扩展组件{
  状态= {
    计数器:0
  };

  处理计数 = () => {
    这个.setState({
      计数器:this.state.counter + 1
    });
  };

  使成为() {
    返回 (
      <div>
        <h1>{this.state.counter}</h1>
        <button onClick={this.handleCount}>计数!!</button>
      </div>
    );
  }
}

现在需要注意的是,此状态仅限于此组件。 计数器中的状态值对子组件或父组件不可用。

因此,在一个更复杂的示例中,如下所示,我们必须将 counter down 的值作为道具传递给子元素。

 类计数器扩展组件{
  状态= {
    计数:0
  };

  处理计数 = () => {
    这个.setState({
      计数:this.state.count + 1
    });
  };

  使成为() {
    返回 (
      <div>
        <PageHeader count={this.state.count} />
        <button onClick={this.handleCount}>计数!!</button>
      </div>
    );
  }
}

每次我们更新 <Counter /> 组件中的状态时,<PageHeader /> 计数属性都会更新

功能页眉(道具){
  返回 <h1>{props.count}</h1>; 
}

这种方法的好处是,无论何时更新状态,都会自动将新值传递给任何子组件,并将 prop 的值设置为 state。

这使我们能够为动态数据提供单点真实性。 事实的来源是状态中的值,由单个组件管理。 子组件中此值的所有实例都是作为 props 接收的不可变值,不应在此组件之外更改。

在层次结构中出现在该组件上方的组件将无法访问此数据,因为它仅通过道具向下传递。 我们再次看到为什么我们尝试从层次结构中更高的组件设置和管理状态,以便数据可供所有需要它的人使用。

还有一些其他的架构模式,比如高阶组件和上下文 API,它们可以避免通过你的应用程序手动传递大量的 props。 稍后我们将更深入地探讨这些。 现在,我们要确保在我们开始走捷径之前,我们了解事物通常如何运作的高级概述。

在 React 中更新组件状态

现在,当我们想要触发从子组件更新状态时会发生什么?

例如,想象一下,在上面的示例中,我们希望在我们的主 <Counter /> 组件中拥有一个 <Button /> 组件而不是硬编码按钮? 这实际上在复杂的应用程序中很常见。

在 React 世界中,解决此问题的方法是传递事件处理函数,该函数使用 setState down 作为 prop 来更新状态。 然后可以从任何子组件调用它,但该操作将发生在设置状态的原始组件中,并且也具有更新它的能力。 存在其他模式,但这种方法是最基本的。

如果您不熟悉将函数作为参数传递,那么它是完全有效的 vanilla JavaScript。

一旦状态更新,它将通过 props 向下传递到组件层次结构。

这是一个看起来像的例子。

 类计数器扩展组件{
  状态= {
    计数:0
  };

  处理计数 = () => {
    这个.setState({
      计数:this.state.count + 1
    });
  };

  使成为() {
    返回 (
      <div>
        <PageHeader count={this.state.count} />
        <Button handleCount={this.handleCount} />        
      </div>
    );
  }
}

功能页眉(道具){ 
  返回( 
    <h1>{props.count}</h1>
 ); 
}

功能按钮(道具){
  返回(
    <button onClick={props.handleCount}>计数!!</button>  
  );
}

在这里,我们可以看到一个 React 如何处理数据流的简单示例。 数据只有一个事实。 这存在于状态集中并从单个组件更新。 数据通过 props 以一种方式向下流过嵌套的组件树。

如果需要从最初设置的组件以外的组件更新状态,则可以将事件处理程序作为道具传递给必要的子组件。 这使数据保持不变并以一种方式流动,因为即使子组件触发更改,该更改也会发生在原始组件的更高位置。

当我们将 prop 的值分配给 state 中的某物时,如下所示,每当 state 发生变化时,该 prop 的值都会自动更新。

 <PageHeader 计数器={this.state.count} />

引用该道具值的任何其他子组件也将自动接收更新。 这就是 React 中数据流的美妙之处。

这可能需要一点时间来适应,具体取决于您过去使用 JavaScript 处理此类问题的方式。 然而,这一切都应该成为我们能够深入解释 React 的一个很好的起点。