` 中,我们只返回一个顶层元素!以下是它在普通的 JavaScript 中的样子:
+
+```
+function LabeledInput({ id, label, ...delegated }) {
+ return React.createElement(
+ 'div',
+ {},
+ React.createElement('label', { htmlFor: id }, label),
+ React.createElement('input', { id: id, ...delegated })
+ );
+}
+
+```
+
+JSX 是一个很棒的抽象,但它常常会掩盖关于 JavaScript 的基本真理。我认为,查看 JSX 如何转换为普通的 JavaScript,以了解实际发生的情况往往是有帮助的。通过这种新的方法,我们返回一个单独的元素,而该元素包含两个子元素。问题解决了!但我们可以使用片段(fragments)进一步改进这个解决方案:
+
+```
+function LabeledInput({ id, label, ...delegated }) {
+ return (
+
+
+
+
+ );
+}
+
+```
+
+`React.Fragment`是一个专门用来解决这个问题的React组件。它允许我们将多个顶级元素捆绑在一起,而不会影响DOM。这非常棒:这意味着我们不会在标记中加入不必要的`
`。它还有一个便捷的简写方式,我们可以像这样编写片段:
+
+```
+function LabeledInput({ id, label, ...delegated }) {
+ return (
+ <>
+
+
+ >
+ );
+}
+
+```
+
+我喜欢这里的符号意义:React团队选择使用一个空的HTML标签`<>`来表示片段不会产生任何实际的标记。
+
+### 7\. 从不受控制变为受控制状态
+
+让我们来看一个典型的表单示例,将一个输入与React状态绑定起来:
+
+```
+import React from 'react';
+
+function App() {
+ const [email, setEmail] = React.useState();
+
+ return (
+
+ );
+}
+
+export default App;
+
+```
+
+你会看到:
+
+
+
+如果你在这个输入框中开始输入,你会注意到控制台上会出现一个警告:
+
+
+
+解决方法如下:我们需要将 `email` 状态初始化为空字符串:
+
+```
+const [email, setEmail] = React.useState('');
+
+```
+
+当我们设置value属性时,我们告诉 React 我们希望这是一个受控输入框。但是,这只有在我们传递一个定义的值时才起作用!通过将email初始化为空字符串,**我们确保 value 永远不会被设置为undefined**。
+
+> 受控输入
+>
+> 如果您想详细了解为什么这是必要的,以及什么是“受控输入”,我们将在我最近发布的教程中深入探讨这些想法:[React中的数据绑定](https://link.juejin.cn/?target=https%3A%2F%2Fwww.joshwcomeau.com%2Freact%2Fdata-binding%2F 'https://www.joshwcomeau.com/react/data-binding/')
+
+JSX 被设计得看起来很像 HTML,但它们之间有一些令人惊讶的差异,往往会让人措手不及。大多数差异都有很好的文档记录,而且控制台的警告通常非常具体和有帮助。例如,如果你意外使用 class 而不是className,React会准确告诉你问题所在。但有一个微妙的差异经常让人困惑:style属性。在HTML中,style是以字符串的形式表示的:
+
+```
+
+
+```
+
+但是,在 JSX 中,我们需要将其指定为一个对象,并带有驼峰属性名称。在下面的代码中,我试图做到这一点,但出现了错误。你能找出错误吗?
+
+```
+import React from 'react';
+
+function App() {
+ return (
+
+ );
+}
+
+export default App;
+
+```
+
+你会看到:
+
+
+
+问题是我需要使用**双波浪线**,如下所示:
+
+```
+
+
+```
+
+为了理解为什么这样是必要的,我们需要稍微了解一下这个语法。在JSX中,我们使用花括号来创建一个表达式插槽。我们可以在这个插槽中放置任何有效的JavaScript表达式。例如:
+
+```
+