React 初学者教程9:从数据到 UI
本文转载自:众成翻译 译者:网络埋伏纪事 链接:http://www.zcfy.cc/article/1539 原文: https://www.kirupa.com/react/from_data_to_ui_in_react.htm
简介:利用 JSX 的灵活性,将烦人的数据转化为甜蜜的 UI 元素。
在创建应用时,术语 props
、state
、组件、JSX 标记、render 方法以及其它 React 主义也许是你脑袋中最后考虑的事情。大部分时间,你是处理 JSON 对象、数组以及其它数据结构形式的数据,这些数据与 React 或者界面无关。跨越数据和最终看到的结果之间的鸿沟可能是令人沮丧的!但是不要担心。本文会通过将你将会遇到的一些常见场景都过一遍,来帮助减少这些令人沮丧的时刻。
示例
为帮助弄清楚你将要看到的所有事情,我们需要一个示例。这也没什么复杂的,所以继续,创建一个新的 HTML 文档,写入如下代码:
<!DOCTYPE html>
<html>
<head>
<title>React! React! React!</title>
<script src="https://fb.me/react-15.0.0-rc.2.js"></script>
<script src="https://fb.me/react-dom-15.0.0-rc.2.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
<style>
#container {
padding: 50px;
background-color: #FFF;
}
</style>
</head>
<body>
<div id="container"></div>
<script type="text/babel">
var Circle = React.createClass({
render: function() {
var circleStyle = {
padding: 10,
margin: 20,
display: "inline-block",
backgroundColor: this.props.bgcolor,
borderRadius: "50%",
width: 100,
height: 100,
};
return (
<div style={circleStyle}>
</div>
);
}
});
var destination = document.querySelector("#container");
ReactDOM.render(
<div>
<Circle bgcolor="#F9C240"/>
</div>,
destination
);
</script>
</body>
</html>
文档写完后,在浏览器中预览一下。一切顺利的话,会看到如下的结果:
现在我们花点时间理解一下这个示例干的是什么。你看到的大部分出自 Circle
组件:
var Circle = React.createClass({
render: function() {
var circleStyle = {
padding: 10,
margin: 20,
display: "inline-block",
backgroundColor: this.props.bgColor,
borderRadius: "50%",
width: 100,
height: 100,
};
return (
<div style={circleStyle}>
</div>
);
}
});
大部分代码是 circleStyle
对象,该对象包含将 div
变成圆的内联样式属性。所有样式值都是硬编码的,除了 backgroundColor
属性,它的值来自传进来的 bgColor
属性。
除了组件,最终把圆显示出来,是通过 ReactDOM.render
方法:
ReactDOM.render(
<div>
<Circle bgColor="#F9C240"/>
</div>,
destination
);
这里我们声明了 Circle
组件的一个实例,并且用 bgColor
属性设置其颜色。现在,让 Circle
组件定义在 render
方法中有一点限制 - 特别是如果你打算处理会影响 Circle
组件的数据。在下面两个小节,我们会看到解决这个问题的方法。
JSX 可以在任何地方
在《深入 JSX》 教程中,我们知道 JSX 实际上是可以放在 render
函数之外,并且可以用作为值,赋值给变量或者属性。例如,我们可以勇敢地像这样做:
var theCircle = <Circle bgColor="<span class="brush:js;html-script:true">#F9C240</span>"/>
ReactDOM.render(
<div>
{theCircle}
</div>,
destination
);
theCircle
变量存储 JSX, 以实例化 Circle
组件。在 ReactDOM.render
函数中计算这个变量,结果会显示一个圆。最终结果与我们前面的示例没有什么不同,但是让 Circle
组件的实例化从 render
方法的束缚中脱离出来,给了我们更多的选择来做一些疯狂而好玩的事情。
例如,你可以进一步创建一个返回 Circle
组件的函数:
function showCircle() {
var colors = ["#393E41", "#E94F37", "#1C89BF", "#A1D363"];
var ran = Math.floor(Math.random() * colors.length);
// return a Circle with a randomly chosen color
return <Circle bgColor={colors[ran]}/>;
};
在这里,showCircle
函数返回一个Circle
组件,该组件的 bgColor
值被设置为一个随机颜色值(棒极了!)。为了让我们的示例使用 showCircle
函数,我们只需要在 ReactDOM.render
内对它求值即可:
ReactDOM.render(
<div>
{showCircle()}
</div>,
destination
);
只要求值的表达式返回 JSX,你就可以在 大括号中放入你想要的很多东西。这种灵活性很好,因为当你的 JavaScript 在 render
函数外生存时,你可以做很多事情。很多事情!
处理数组
现在我们开始做点有趣的事情。当你想显示多个组件时,你不能总是像这样手动指定它们:
ReactDOM.render(
<div>
{showCircle()}
{showCircle()}
{showCircle()}
</div>,
destination
);
在很多真实场景下,要显示的组件的数量与在一个数组或者类数组(比如迭代器)对象中的条目数量有关。这带来一些简单的并发症(复杂性)。例如,假如我们有如下 colors
数组:
var colors = ["#393E41", "#E94F37", "#1C89BF", "#A1D363",
"#85FFC7", "#297373", "#FF8552", "#A40E4C"];
我们想为这个数组中的每个条目创建一个 Circle
组件,并把 bgColor
属性设置为每个数组条目的值。为实现这个目的,我们打算创建一个 Circle
组件数组:
var colors = ["#393E41", "#E94F37", "#1C89BF", "#A1D363",
"#85FFC7", "#297373", "#FF8552", "#A40E4C"];
var renderData = [];
for (var i = 0; i < colors.length; i++) {
renderData.push(<Circle bgColor={colors[i]}/>);
}
在这段代码中,我们用 Circle
组件填充 renderData
数组,就像开始我们所做的一样。要显示所有这些组件,在 React 中就很简单。我们看看如下代码行:
var colors = ["#393E41", "#E94F37", "#1C89BF", "#A1D363",
"#85FFC7", "#297373", "#FF8552", "#A40E4C"];
var renderData = [];
for (var i = 0; i < colors.length; i++) {
renderData.push(<Circle bgColor={colors[i]}/>);
}
ReactDOM.render(
<div>
{renderData}
</div>,
destination
);
在 render
方法中,我们把 renderData
数组指定为需要求值的表达式。要实现如下效果,我们不需要采用任何其它步骤:
好吧,我说谎了。这里实际上我们还需要做一件事情,并且是很不容易察觉的事情。React 之所以让 UI 更新很快,是通过清楚地了解 DOM 中到底发生了什么。它用几种方式去了解,但是真正值得关注的一个方式是,通过内部用某种标识符标记每个元素。
当动态创建元素时(比如我们在 Circle
组件数组中所做),这些标识符不是自动设置的。我们需要做一些额外的工作。这种额外的工作采用 key
属性的形式,React 用 key
属性的值来唯一地识别每个特殊的组件。
对于我们的示例,我们可以像这样做:
for (var i = 0; i < colors.length; i++) {
var color = colors[i];
renderData.push(<Circle key={i + color} bgColor={color}/>);
}
在每个组件上,我们指定 key
属性,并将其值设置为 colors
数组内的 color
和索引位置的组合。这确保我们动态创建的每个组件最终有一个唯一的标识符,随后 React 就可以用这个唯一的标识符来优化任何将来的 UI 更新。
检查你的控制台!
React 相当擅长当你做错了事时告诉你。例如,如果你动态创建元素/组件,但是没有为它们指定一个 key 属性,你会在控制上中得到如下警告:
Warning: Each child in an array or iterator should have a unique "key" prop. Check the top-level render call using .
使用 React 时,周期性地检查控制台消息是个好主意。
总结
在本文中你所看到的所有诀窍都可能是由一个东西造成:JSX 就是 Javascript。这就是为什么 JavaScript 出现的地方都可以用 JSX 的原因。对于我们来说,下面这样的代码看起来是相当怪异的:
for (var i = 0; i < colors.length; i++) {
var color = colors[i];
renderData.push(<Circle key={i + color} bgColor={color}/>);
}
尽管我们把一些 JSX 判断压到一个数组中,像变戏法一样,当 renderData
在 render
方法内被求值时,所有代码都能正常运行。我讨厌听起来像坏唱片一样,但是这是因为我们的浏览器最终看起来像这样子:
for (var i = 0; i < colors.length; i++) {
var color = colors[i];
renderData.push(React.createElement(Circle,
{
key: i + color,
bgColor: color
}));
}
当 JSX 被转换为纯 JS 时,一切又变得有意义。这就是为什么我们可以将 JSX 和 数据一起放在各种不舒服的条件下,但是依然可以得到我们想要的最终结果的原因。因为,最终,都是 JavaScript。
React初学者系列教程
- 第 1 篇:React 简介
- 第 2 篇:创建第一个 React 应用
- 第 3 篇:React 中的组件
- 第 4 篇:在 React 中设置样式
- 第 5 篇:创建复杂的组件
- 第 6 篇:传递属性
- 第 7 篇:深入JSX
- 第 8 篇:处理状态
- 第 9 篇:从数据到 UI
- 第 10 篇:React 中的事件
- 第 11 篇:组件生命周期
- 第 12 篇:用 React Router 创建单页应用
- 第 13 篇:用 React 常见一个简单的 Todo List 应用
- 第 14 篇:在 React 中访问 DOM 元素
- 第 15 篇:设置 React 开发环境nike air max 1 Classic