你能在 JSX 中使用 console.log 吗?

3,064 阅读2分钟

引言

作为 React 的初学者,往往会写出以下代码:

render() {
  return (
    <div>
      <h1>List of todos</h1>
      console.log(this.props.todos)
    </div>
  );

这样做将不会在控制台上打印出你所期望的 todos 信息,它只会在浏览器中渲染出字符串 console.log(this.props.todos)

解决方案

最常用的方案

在你的 JSX 代码中嵌入表达式:

render() {
  return (
    <div>
      <h1>List of todos</h1>
      { console.log(this.props.todos) }
    </div>
  );
}

另一个受欢迎的方案

将你的 console.log 放置于 return() 之前:

render() {
  console.log(this.props.todos);
  return (
    <div>
      <h1>List of todos</h1>
    </div>
  );
}

新颖的方案

我们完全可以定制一个 <ConsoleLog> 组件:

const ConsoleLog = ({ children }) => {
  console.log(children);
  return false;
};

然后在需要的时候引入该组件:

render() {
  return (
    <div>
      <h1>List of todos</h1>
      <ConsoleLog>{ this.props.todos }</ConsoleLog>
    </div>
  );
}

这一切如何解释

首先,JSX 不是原生的 JavaScript,也不是 HTML,它是一种拓展语言。

拓展语言是指需要经过编译后才能被浏览器执行的语言,比如我们熟知的样式预处理器:sass,采用该语言编写的样式文件,后缀名为 .scss,经过 webpack 中 sass-loader 的处理,最终转换为浏览器可以理解的 .css 文件

相同的,.jsx 最终会被编译为原生的 .js。举个🌰,我们在 JSX 写入:

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);

它将最终被编译为:

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

这一切都是 Babel(下一代 JavaScript 编译器)在背后做的功劳,大家可以打开 Babel/repl 亲自试一试。

我们来看 React.createElement 的每个参数代表了什么?

  • 'h1' : 标签的名称,是一个字符串
  • { className: 'greeting' } : 将 <h1> 的属性转化为对象,例如 className,事件处理器,props
  • 'Hello, world!' : 被叫做 children,包含 <h1> 标签内的所有子内容

我们将视线转向文章开头的代码:

<div>
  <h1>List of todos</h1>
  console.log(this.props.todos)
</div>

会被最终编译为:

// 当包含多个子元素时,children将视为一个数组
React.createElement(
  'div',
  {}, // 没有属性
  [ 
    React.createElement( // 遇到新标签h1,再次执行React.createElement
      'h1',
      {}, // 同样没有属性
      'List of todos',
    ),
    'console.log(this.props.todos)'
  ]
);

结尾

当你想使用 console.log 时,只需将代码嵌入到 {}

原文链接:Can you console.log in JSX?