React中的容器组件教程

327 阅读5分钟

React中的容器组件

当你使用React构建应用程序时,你应该考虑到数据是如何在应用程序的不同组件之间传递的。

在这篇文章中,我们将通过构建一个使用容器组件React模式的搜索组件,来了解什么是容器组件以及它们是如何工作的。

前提条件

在你阅读本文之前,你需要对以下内容有一个概念。

  • [什么是React]。
  • 你可以阅读[如何用Parcel创建一个React应用],或者直接使用[CRA:创建React应用]。
  • [如何利用React Hooks]在组件中存储状态
  • [理解组件和Props是如何一起工作]的。

当你搞清楚这些概念后,你可以回到这里来阅读这篇文章。

它们到底是什么?

丹-阿布拉莫夫(Dan Abramov)在强调React应用中关注点分离的概念时,使用了 "容器组件 "这一术语。

容器组件总是负责一个组件中的工作方式。- 丹-阿布拉莫夫

当我们想到 "容器 "这个词的时候,我们脑海中浮现的第一件事就是这个词的理想代表,它是一个储存和或容纳内容的实体或材料。这种容器所容纳的内容类型可能有所不同。

React中的**"容器组件 "**也是如此。容器组件主要可以被称为React应用程序中其他组件的父元素。它们是渲染用户界面的普通组件和使用户界面组件互动和动态的逻辑之间的桥梁。

容器组件最常见的功能是获取数据。获取数据并不是指从API的端点获取数据的传统方式,它也与React组件的逻辑有关。

一旦在组件中执行逻辑或获取数据的过程完成。它就会渲染相应的组件 有时,容器组件可以执行两种功能(即渲染UI和保持逻辑)。

在一个容器组件执行这些的情况下。该组件本身并不持有过多的标记(JJSX),也没有CSS样式。

下面是一个例子。

import React from “react”

export const exampleComponent = ({ children }) => {
  const open = () => {
    alert("You clicked this container component")
  }

  return (
    <div onClick={open}>
	{children}
    </div>
  );
};

上面的组件说明了一个容器组件如何执行两个功能,呈现UI和处理组件的逻辑。

如果你看一下上面的组件,你会发现它利用props在 "任意 "React应用中的组件之间分享数据。

**注意:**在开发者社区有一个惯例是很常见的。

开发者倾向于把他们的容器组件放在一个单独的文件夹里,而把UI组件放在另一个文件夹里,这样他们就可以区分这些组件了。如果你已经有一个对你来说很好用的文件夹,你可以选择不遵循这种创建不同文件夹的模式,只要你能够解决同样的问题。

建立搜索组件

搜索组件是典型的React应用中最普遍的组件之一。

在我们开始构建这个应用程序之前,让我们看看包含所有文件的文件夹结构是如何表示的。如果你已经有了适合你的结构,你不需要再去使用这种类型的结构。

我们的目标只是为了能够了解项目的整个流程。

src
 |-- App.js
 |-- bookshelf.js
 |-- components
           |---- Books.js
           |---- Search.js

让我们先考虑一下搜索组件所要执行的功能。一个搜索组件应该能够执行基本的任务,如搜索和过滤。

为了保持简单,让我们使用一个对象数组作为搜索的数据,而不是使用一个API。

让我们创建一个对象数组,其中包含关于书籍的简单信息,这些信息将在这个组件中出现。

// bookshelf.js
export const books = [
  {
    name: "Eloquent JavaScript",
    author: "Marijn Haverbeke",
  },
  {
    name: "CSS The Definitive Guide",
    author: "Eric A. Meyer & Estelle Weyl",
  },
  {
    name: "Automate the boring stuff with Python",
    author: "Al Sweigart",
  },
  {
    name: "Make: JavaScript Robotics",
    author: "Donovan Buck, Bryan Hughes et al",
  },
];

bookshelf.js 文件中的数据将作为这些信息。一旦用户开始在输入框中输入,搜索组件应该能够过滤书籍列表。

让我们在下面创建这个应用程序所需的组件,我将解释一切如何运作。

Search 组件向用户展示用户界面(即它渲染了一个输入元素,用户可以在其中过滤列表中的书籍。

// search.js
import React from “react”

const Search = ({ val, onSearch, ...props }) => {
  return (
    <input
	  value={val}
	  onChange={onSearch}
	  placeholder="Search for any book"
	  {...props}
    />
  );
};

export default Search

Books 组件执行的功能与搜索组件几乎相同。大多数人把这种类型的组件称为"哑巴"、"无状态 "或 "呈现性"组件。

这是因为它们只关心应用程序的用户界面是如何被渲染或显示给用户的。

它们并不总是有一个状态,相反,它们使用来自组件的父级的道具来获取应用组件树中的数据。

// books.js

import React from "react";

const Books = ({ books }) => {
  return books.map((book, index) => {
    return (
      <ul key={index}>
        <li>Book: {book.name}</li>
        <li>Author: {book.author}</li>
      </ul>
    );
  });
};
export default Books;

App 组件说明了一个容器组件如何执行两种功能,渲染用户界面和容纳该容器的逻辑。

用户在输入框中输入的文本以字符串的形式存储在App 组件的状态中,这样我们就能够使用过滤器方法对书籍进行过滤。

这是有可能的,因为传递给Book 组件的数据也在这个容器组件中被控制。

因此,每次输入字段检测到一个字符时,它就开始在搜索词和books 数组中的所有项目中循环,看哪一个与文本相匹配,并将其渲染到DOM中。

import React, { useState } from "react";
import { books } from "./bookshelf.js";
import Books from "./Books";
import Search from "./Search";

const App = () => {
  const [searchTerm, setSearchTerm] = useState("");
  const handleInputChange = (e) => {
    setSearchTerm(e.target.value);
  };
  // performs a filtering on the questions
  // based on the user's input and returns a new array
  // which gets rendered to the DOM.

  const filteredBooks = books.filter((book) => {
    return book.name.includes(searchTerm);
  });
  return (
    <section>
      <Search name="search" onSearch={handleInputChange} val={searchTerm} />
      <Books books={filteredBooks} />
    </section>
  );
};
export default App;

总结

这个范式背后的想法是能够采用 "关注点分离 "模式。

通过采用这种模式,开发人员能够以一种可重复使用和可扩展的方式来构建应用程序中的组件。

感谢你阅读这篇文章,直到这一点。请与你的同行们分享它。