React 编程思想 #1

React 编程思想 #1

看太多语法,都不如简单尝试一下,跟着官方文档做了一下 DEMO,文档写的真不错,就是没翻译完,一大半都还是英文(×_×),本篇其实大部分也是在重复文档内容,不过加上了自己的尝试。

从原型开始

React 可以改变你对所看到的设计以及所构建的应用程序的看法。以前你看到的是一片森林,使用 React 后,你将欣赏到每一棵树。React 简化了你对设计系统(design system)和 UI 状态的看法。在本教程中,我们将带领你使用 React 构建一个可搜索的数据表产品,并领略整个思考的过程。

以上来自 React 的官方文档( https://react.bootcss.com/learn/thinking-in-react# ),形容的可以说是非常好了。React 的编程思想就是如何从控件(树)到应用(森林)。

首先假设开发界面时已经拥有了 API 返回的数据(或者模拟出来的):

[
  { category: "Fruits", price: "$1", stocked: true, name: "Apple" },
  { category: "Fruits", price: "$1", stocked: true, name: "Dragonfruit" },
  { category: "Fruits", price: "$2", stocked: false, name: "Passionfruit" },
  { category: "Vegetables", price: "$2", stocked: true, name: "Spinach" },
  { category: "Vegetables", price: "$4", stocked: false, name: "Pumpkin" },
  { category: "Vegetables", price: "$1", stocked: true, name: "Peas" }
]

同时也有了设计师设计的原型,原型中除了对数据的显示,还要有搜索栏和单选框实现过滤的需求:

有了这两个东西,就可以进行代码的设计了。首先,从构建 UI 开始,按照 React 的思想,需要将 UI 细分成多个组件,文档中的分法是分成了五个组件:

这五个组件是:

  1. FilterableProductTable (灰色部分)包含了整个应用程序。
  2. SearchBar (蓝色部分)接收用户输入。
  3. ProductTable (紫色部分)根据用户的输入显示和筛选列表。
  4. ProductCategoryRow (绿色部分)显示每个类别的标题。
  5. ProductRow (黄色部分)每行显示一个产品。

根据组件之间的包含关系,可以区分出它们的层级:

  • ——FilterableProductTable
  • ————SearchBar
  • ————ProductTable
  • ——————ProductCategoryRow
  • ——————ProductRow

划分了界面的组件和组件关系后,就可以进行编码了。

静态实现

首先进行界面的静态实现,即简单显示内容,不包含交互操作。React 构建的应用,画面由组件转换为 HTML 代码渲染出来(不知道的话先看入门把 https://react.bootcss.com/learn ),因此,可以将一个个组件理解为一段段的 HTML 代码块。父组件包含子组件,就好像 HTML 标签之间的嵌套。这里的思想和 DOM 的思想是一样的(个人理解)。

对于简单的应用,自顶向下构建组件更加简单,而复杂的应用自底向上构建组件更加简单。这个 DEMO 自然是简单的应用,因此直接从最大的组件 FilterableProductTable 开始构建:

  function FilterableProductTable({products}) {
    return (
      <div>
        <SearchBar />
        <ProductTable products={products} />
      </div>
    );
  }

分析一下这段代码,整体看这段代码是一个 JS 函数,返回了一段 HTML 代码,这就是一个组件了;其中,包含了两个子组件 SearchBarProductTable,与上面划分的组件结构一致;这个函数的参数是 {products},即商品列表,在后面,又将这个参数传递给了 ProductTable,这也是 React 的一个特点:数据自顶向下流动,即数据由父组件传递给子组件。

多说一句,这里参数传递的方式是 {products},加上了花括号,因为如果没有花括号,React 会认为这是一整个 props 属性,如这样:

  // 不加花括号,传递的是 props,后续还要在 props 中获取 products
  function FilterableProductTable(props) {
    return (
      <div>
        <SearchBar />
        <ProductTable products={props.products} />
      </div>
    );
  } 

继续其他组件的构建,这里就不多说了,最后构建出的整个 JS 文件如下:


function ProductCategoryRow({ category }) {
    return (
      <tr>
        <th colSpan="2">
          {category}
        </th>
      </tr>
    );
  }
  
  function ProductRow({ product }) {
    const name = product.stocked ? product.name :
      <span style={{ color: 'red' }}>
        {product.name}
      </span>;
  
    return (
      <tr>
        <td>{name}</td>
        <td>{product.price}</td>
      </tr>
    );
  }
  
  function ProductTable({ products }) {
    const rows = [];
    let lastCategory = null;
  
    products.forEach((product) => {
      if (product.category !== lastCategory) {
        rows.push(
          <ProductCategoryRow
            category={product.category}
            key={product.category} />
        );
      }
      rows.push(
        <ProductRow
          product={product}
          key={product.name} />
      );
      lastCategory = product.category;
    });
  
    return (
      <table>
        <thead>
          <tr>
            <th>Name</th>
            <th>Price</th>
          </tr>
        </thead>
        <tbody>{rows}</tbody>
      </table>
    );
  }
  
  function SearchBar() {
    return (
      <form>
        <input type="text" placeholder="Search..." />
        <label>
          <input type="checkbox" />
          {' '}
          Only show products in stock
        </label>
      </form>
    );
  }

  function FilterableProductTable({products}) {
    return (
      <div>
        <SearchBar />
        <ProductTable products={products} />
      </div>
    );
  }
  
  const PRODUCTS = [
    {category: "Fruits", price: "$1", stocked: true, name: "Apple"},
    {category: "Fruits", price: "$1", stocked: true, name: "Dragonfruit"},
    {category: "Fruits", price: "$2", stocked: false, name: "Passionfruit"},
    {category: "Vegetables", price: "$2", stocked: true, name: "Spinach"},
    {category: "Vegetables", price: "$4", stocked: false, name: "Pumpkin"},
    {category: "Vegetables", price: "$1", stocked: true, name: "Peas"}
  ];
  
 function App() {
    return <FilterableProductTable products={PRODUCTS} />;
  }

可以看到,组件之间的关系和之前划分的组件结构一致,父组件包含着子组件,子组件之间也可能是兄弟,和 HTML 标签之间的关系是一致的。

SearchBar 组件中,显示了搜索框和单选框,没有其他的子组件,但也仅仅是显示,还没有交互的功能;ProductTable 组件是一个表格,其中,包含了多个 ProductRowProductCategoryRow 组件,这两个组件即商品行和商品目录行,其内容是根据参数 products 进行动态渲染的。

最后,构建了一个 APP 组件,包含了最大的组件 FilterableProductTable 并第一次传递了参数 PRODUCTS,这就是应用(森林)了。

构建完应用后,还需要将其渲染到页面上,参考代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello Qyc!</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel" src="./reactTest2.js"></script>
</head>
<body>

<div id="example"></div>

<script type="text/babel">

    ReactDOM.render(<App />, document.getElementById('example'))

</script>

</body>
</html>

reactTest2.js 文件就是上面构建的应用所在的文件,通过引入 React 和这个 JS 文件,可以使用 ReactDOM.render 方法将其渲染到页面上的占位符 example 上(这就是基础了,不多说)。

这里踩到个坑:在 VSCode 中启动 HTML 页面,会报错 CORS(跨域访问错误),这是由于 HTML 页面是通过 file:// 访问的,JS 文件也是通过 file:// 访问的,触发了浏览器的安全保护策略。在研究了半天后,发现可以通过搭建服务器,转换为 http:// 访问解决。但因为一些特殊原因,我这用不了 npm,装不了 http-server,很搞。还好最后在 VSC 里发现了个插件 Live Server,可以直接转换为本地服务器启动,最终也是起起来了。

最后实现的效果就是这样啦:

在本地跑起来感觉还是不一样的。

posted @   Qirror  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
Live2D
欢迎阅读『React 编程思想 #1』
点击右上角即可分享
微信分享提示