【全栈React】第13天: 重复元素

本文转载自:众成翻译
译者:iOSDevLog
连接:http://www.zcfy.cc/article/3826
原文:https://www.fullstackreact.com/30-days-of-react/day-13/javascript

今天,咱们将经过如何显示多个组件来准备将外部数据引入咱们的应用。html

咱们已经构建了一个没有任何外部数据的基本应用。在咱们实现以前 (咱们将在明天开始这个功能), 让咱们来看看过去两周中咱们所掩盖的事情:java

重复元素

咱们已经看到了这以前, 咱们已经遍历了一个对象列表, 并在屏幕上呈现多个组件。在咱们的应用中添加太多的复杂度来加载外部数据以前, 今天咱们将快速了解如何在应用中重复组件/元素。react

因为 jsx 被浏览器视为纯 javascript 的, 咱们可使用任何 传统 javascript 内的模板标签中的 jsx。咱们已经看到了这一行动。做为一个快速演示:git

const App = (props) => {
  return (
    <ul>
      {a.map(i => {
        return <li>{i}</li>
      })}
    </ul>
  )
}

注意模板标签{} 内的内容看起来简单的 javascript。那是由于它 只是 javascript。此功能容许咱们使用 (大多数) 的 javascript 在咱们的模板标签 包括 原生迭代器, 如 mapforEachgithub

让咱们来看看这是什么意思。让咱们将上一个示例的 a 值从单个整数转换为整数列表:web

const a = [1, 10, 100, 1000, 10000];

咱们能够将 a 变量映射到咱们的组件中, 并返回将为咱们构建虚拟 DOM 的响应组件列表。npm

const App = (props) => {
  return (
    <ul>
      {a.map(i => {
        return <li>{i}</li>
      })}
    </ul>
  )
}

什么是map() 函数?api

map() 函数是数组中一个原生javascript内置函数的。
它接受在数组的每一个元素上运行的函数, 所以, 上面的函数将运行四次, 其值为i 开始为1 , 而后它将再次运行它的第二个值, i将被设置为10 等等等等。数组

让咱们更新咱们在第12天建立的应用与咱们的 App 组件在这里。让咱们打开咱们的src/App.js 文件, 并将 App 组件的内容替换为此源。清理一些未使用的变量和您的src/App.js应该相似于如下内容:

import React from 'react';

const a = [1, 10, 100, 1000, 10000];
const App = (props) => {
  return (
    <ul>
      {a.map(i => {
        return <li>{i}</li>
      })}
    </ul>
  )
}

export default App

使用create-react-app命令生成的命令再次启动应用:npm start, 咱们能够看到应用在浏览器中工做!

可是, 若是咱们打开开发人员控制台, 咱们将看到打印出错误。此错误是由如下事实引发的: React不知道如何跟踪咱们列表中的各个组件, 由于它们只是看起来像一个 <li />组件。

出于性能缘由, React使用虚拟 DOM 尝试限制在从新视图时须要更新的 DOM 元素的数量。若是没有任何变化, React不会使浏览器更新任何东西以节省工做。

此功能很是适合于构建 web 应用, 但有时咱们必须经过为节点提供惟一标识符来帮助作出React。在映射列表和渲染组件是其中之一。

React要求咱们经过使用特殊属性来识别唯一的组件, 这是列表中每一个元素的 key 属性。key 属性能够是任何咱们想要的, 但它 必须是惟一的 的元素。在咱们的示例中, 咱们能够在 map 中使用i变量, 由于数组中没有其余元素具备相同的值。

让咱们更新映射来设置key:

const App = (props) => {
  return (
    <ul>
      {a.map(i => {
        return <li key={i}>{i}</li>
      })}
    </ul>
  )
}

子组件

咱们在本周早些时候谈到了创建父子关系的事情, 可是让咱们更详细地介绍一下如何访问父组件中的子组件, 以及如何呈现它们。

在第11天, 咱们构建了一个 <Formatter />组件来处理时钟组件中的日期格式, 以使用户可以灵活地使用本身的自定义时钟渲染。回想一下, 咱们所建立的实现其实是至关丑陋和相对复杂的。

const Formatter = (props) => {
  let children = props.format.split('').map((e, idx) => {
    if (e === 'h') {
      return <Hour key={idx} {...props} />
    } else if (e === 'm') {
      return <Minute key={idx} {...props} />
    } else if (e === 's') {
      return <Second key={idx} {...props} />
    } else if (e === 'p') {
      return <Ampm key={idx} {...props} />
    } else if (e === ' ') {
      return <span key={idx}> </span>;
    } else {
      return <Separator key={idx} {...props} />
    }
  });

  return <span>{children}</span>;
}

咱们能够用React.Children 对象来映射一个React对象的列表, 并让React作这个自举。其结果是一个更干净的 Formatter组件 (不是完美的, 但可以使用的):

const Formatter = ({format, state}) => {
  let children = format.split('').map(e => {
    if (e == 'h') {
      return <Hour />
    } else if (e == 'm') {
      return <Minute />
    } else if (e == 's') {
      return <Second />
    } else if (e == 'p') {
      return <Ampm />
    } else if (e == ' ') {
      return <span> </span>;
    } else {
      return <Separator />
    }
  });
  return (<span>
      {React.Children
        .map(children, c => React.cloneElement(c, state))}
      </span>)
}

React.cloneElement

咱们尚未谈论React.cloneElement() 函数, 因此让咱们简单地看看它。
记得 WWWWWAAAAAYYYYY(way) 回到第2天, 咱们看了如何浏览器 看待 JSX? 它把它变成了相似于以下的 javascript:

React.createElement("div", null, 
  React.createElement("img", {src: "profile.jpg", alt: "Profile photo"}),
  React.createElement("h1", null, "Welcome back Ari")
);

React.cloneElement() 为咱们处理这个。有时咱们会想复制它或添加自定义props/children的组件,而不是建立一个新的组件实例 (若是咱们已经有一个)。因此咱们能够保留它建立的相同的属性。咱们能够用React.cloneElement() 来为咱们处理这一切。

React.cloneElement()React.createElement() 函数有相同的api,参数所在的位置:

  1. 咱们要克隆的 ReactElement
  2. 咱们要添加到实例中的任何 props
  3. 咱们但愿它有任何children

在咱们的 Formatter 示例中, 咱们正在建立列表中全部子级 (<Hour />, <Minute />等组件) 并将state 对象做为其属性。

React.Children 的对象提供了一些很好的实用工具来处理children的函数。上面的 Formatter 示例使用 map 函数循环访问子级, 并在列表中克隆每个。它为每个建立一个key (若是须要), 使咱们没必要本身管理惟一性。

让咱们使用React.Children.map() 函数更新咱们的应用组件:

const App = (props) => {
  return (
    <ul>
      {React.Children.map(a, i => <li>{i}</li>)}
    </ul>
  )
}

在浏览器中, 一切仍然正常。

React.Children 中还有其余一些很是有用的方法,咱们将主要使用React.Children.map() 函数,但了解其余可用的 对咱们来讲也是很好的。 点击文档 查看更多列表。

经过这一点, 咱们只处理了本地数据, 而不是真正关注远程数据 (尽管咱们在构建活动提要组件时 已经 简要地提到了它)。明天, 咱们将进入与服务器的互动, 因此咱们可使用它在咱们的React应用。

今天的工做很棒!

相关文章
相关标签/搜索