为什么在 JSX 中只能使用表达式,而不能使用语句?

IT技术 javascript reactjs
2021-04-30 14:34:12

在继续之前,我应该提到是的,我已经阅读了关于“在 React JSX 中使用 if 语句”及其在 SO 和其他地方的不同变体的问题和答案

然而,这些帖子更多地是关于如何在不使用 JSX 中的语句的情况下绕过。我想知道为什么JSX 中不允许使用语句,对此我找不到任何帖子。

我正在阅读关于这个名为“ If-Else in JSX的官方文档,给出的原因是,引用,

JSX 只是函数调用和对象构造的语法糖

他们继续对比以下两段代码,其中第一段有效,第二段无效:

这是有效的:

// This JSX: 
ReactDOM.render(<div id="msg">Hello World!</div>, mountNode);
// Is transformed to this JS: 
ReactDOM.render(React.createElement("div", {id:"msg"}, "Hello World!"), mountNode); 

这是无效的:

// This JSX:
<div id={if (condition) { 'msg' }}>Hello World!</div>

// Is transformed to this JS:
React.createElement("div", {id: if (condition) { 'msg' }}, "Hello World!");

我真的很想在幕后了解这一点。首先,在第二个示例中,我从未想过在idHTML 元素属性中编写 JavaScript 事实上,这是我第一次看到 id 属性中使用的任何类型的代码。如果我要尝试编写一个 if 条件,我只会在渲染返回表达式中的花括号中完成它,作为其他有效的 JS(如映射或三元表达式)的简单模拟。

render() {
return (
  {if ...
}
)

我毫不怀疑,本文档的作者非常清楚这个略显非正统的例子解释了他们的断言“JSX 只是函数调用和对象构造的语法糖”,但我无法弄清楚如何。

2个回答

让我们从概念上开始。语句与表达式的定义是什么?

一个语句做某事。表达式的计算结果为一个值。

JSX 旨在构建并从一段代码传递到另一段,最终以 HTML 结束。这个名字甚至暗示了这种“JavaScript 到 XML”的转换。

它的全部意义在于返回 HTML 节点的“值”。JSX 允许使用表达式,因为它们可以帮助您确定值。

也许仔细研究一下三元表达式和 if/else 之间的区别会有所帮助。

如果别的

if(isSaturday){
   wakeUpHour = 10;
}else{
   wakeUpHour = 7;
}

三元

wakeUpHour = isSaturday ? 10 : 7;

他们都完成了同样的事情,对吧?但在引擎盖下,他们的运作方式有所不同。在英语中,if/else 可能会读作:

  1. 如果 'isSaturday' 的值为真,则运行花括号内的代码
  2. 将数字 10 分配给“wakeUpHour”
  3. 否则,运行下一个大括号内的代码
  4. 将数字 7 分配给“wakeUpHour”

三元语句也有两部分:

  1. 如果 isSaturday 为真,则值为 10。否则值为 7。
  2. 将此值分配给“wakeUpHour”

我们认为这些都是在完成同样的事情。这里的关键是三元表达式本身只是一个值这不是代码行。使用该值做某事需要另一部分,分配它。

在 JSX 中,我们不想分配东西。我们想要value观。所以我们只是采用三元表达式(一个值),而不是赋值部分或任何其他代码语句。

最后,希望不要增加您的困惑,我要指出您可以在 JSX 中定义函数。

const myJSX = <button onClick={ () => { return 'hello'; } }>Say hello</button>

等等,什么?我以为我们无法执行代码行。它不是执行代码行,而是定义它们;它呈现为:

var myJSX = React.createElement("button", {onClick: () => {
  return 'hello';
}}, "Say hello");

将其与尝试仅放入 if/else 语句进行比较:

const myJSX = <span>{ if(true){ return 'hello'; } }</span>

这将尝试呈现为:

var myJSX = React.createElement("span", null, if(true){ return 'hello' });

这是行不通的,原因与您通常无法将未封装的代码块传递给函数的参数相同。

也许这与您的问题无关,但我已被重定向到这里,因为我的一个问题据说与您的问题重复。如果你想做多行 JavaScript 代码,你可以用 IIFE 包装你的 JS 代码,例如:

  <b>
    {(() => {
      const a = [1, 2, 3].find((el) => el === 2)
      // as much code as you want ...
      // ...
      // ...
      console.log(a)
    })()}
  </b>