本文转载自:众成翻译
译者: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 在咱们的模板标签 包括 原生迭代器, 如 map
和 forEach
。github
让咱们来看看这是什么意思。让咱们将上一个示例的 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,参数所在的位置:
- 咱们要克隆的 ReactElement
- 咱们要添加到实例中的任何
props
- 咱们但愿它有任何
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应用。
今天的工做很棒!