Skip to main content

JSX

react-cover

JSX

What's JSX?

const element = <h1>Hello, world!</h1>;

JSX, 乍看起来可能比较像是模版语言,但本质上是 JS 的一种扩展,完全是在 JS 内部实现的。 主要用来描述用户界面,常见于 render 方法里面的 return 和一些用户界面相关变量定义。

你可以任意地在 JSX 当中使用 JS 表达式,在 JSX 当中的表达式要包含在单大括号 {}里。

tip

对于需要换行的 JSX 代码,在其外面加上一个小括号()

这样可以防止 分号自动插入 的 bug,且便于 JSX 代码的换行对齐。

Props

你可以使用引号来定义以字符串为值的属性:

const element = <div tabIndex="0"></div>;

也可以使用大括号来定义以 JS 表达式为值的属性:

const element = <img src={user.avatarUrl}></img>;
caution

使用大括号包裹的 JS 表达式时外面还有引号包裹。

因为 JSX 会将引号当中的内容识别为字符串而不是表达式。

tip

使用 camelCase 小驼峰命名来定义属性的名称,而不是使用 HTML 的属性名称。

因为 JSX 的特性更接近 JavaScript 而不是 HTML 。

Nesting

如果 JSX 标签是闭合式的,那么你需要在结尾处用 />, 就好像 XML/HTML 一样:

const element = <img src={user.avatarUrl} />;

JSX 标签同样可以相互嵌套:

const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);

JSX is Object

Babel 转译器会把 JSX 转换成一个名为 React.createElement() 的方法调用。

下面两种代码的作用是完全相同的:

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

React.createElement() 这个方法首先会进行一些避免 bug 的检查,之后会返回一个类似下面例子的对象:

// 注意: 以下示例是简化过的(不代表在 React 源码中是这样)
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world'
}
};

这样的对象被称为 “React 元素”。它代表所有你在屏幕上看到的东西。React 通过读取这些对象来构建 DOM 并保持数据内容一致。

有关元素渲染更新的内容请参考:React 官方文档:元素渲染

Conditional rendering

条件渲染大体有两种,一种是 JS 写法,它在 render 方法里面写多个 return 语句,那么你可以将逻辑放在 JS 中判断,和一般的 JS 中的 if-else 语句写法无异。另一种就是 JSX 写法,render 方法里面只有一个 return 语句,可以通过用 单大括号 {} 包裹代码在 JSX 中嵌入任何 JS 表达式,这种相对更为简洁。当然也可以采用两种组合式的写法。

Using condition in JS

const renderComponent = props => {
if (props.isFirstTime) {
return (
<div>
This is homepage
<span>Hello, World</span>
</div>
);
}
return <div>This is homepage</div>;
};
tip

一般开发中建议不要使用该写法,除非不同条件下 return 的 v-dom 没有公共部分。

Using condition in JSX: &&

const renderComponent = props => {
return (
<div>
This is homepage
{!!props.isFirstTime && <span>Hello, World</span>}
</div>
);
};
tip

逻辑与运算要使用 !! 进行显式强制转换,防止某些假值被渲染出来,demo

Using condition in JSX: ? :

const renderComponent = props => {
return (
<div>
This is homepage
{props.isFirstTime ? (
<span>Hello, World</span>
) : (
<span>See you again</span>
)}
</div>
);
};
tip

三目运算的判断可以不用加 !! ,因为其肯定会渲染后面二者之一。

Rendering as a list

map

列表的渲染要使用 JS 数组实例方法 .map() ,不能使用 forEach,因为它不会将需要渲染的 react-dom return 出来,而 map 是有返回值的。

const renderListItems = props => {
const numbers = [1, 2, 3, 4, 5];
return (
<ul>{numbers.map((number) => <li>{number}</li>}</ul>
)
}

key

写动态子组件时,如果没有给动态子项添加 key prop,则会报一个警告:

Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of 'renderListItems'. See [https://fb.me/react-warning-keys](https://fb.me/react-warning-keys) for more information.

这个警告指的是,如果每一个组件是一个数组或迭代器的话,那么必须有一个唯一的 key prop。那么这个 key prop 是做什么的?

  • react 利用 key 来识别组件,它是一种身份标识。keys 是 react 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识。
  • react 根据 key 来决定是销毁重新创建组件还是更新组件

直接用数组的 index 是非常低效的做法。我们在生产环境下常常犯这样的错,这个 key 是每次用来做 Virtual-Dom diff 的,如果使用 index 作为 key 就相当于用了一个随机键,那么不论有没有相同的项,更新都会重新渲染。

在 React Diff 算法中 React 会借助元素的 Key 值来判断该元素是新近创建的还是被移动而来的元素,从而减少不必要的元素重渲染。此外,React 还需要借助 Key 值来判断元素与本地状态的关联关系,因此我们绝不可忽视转换函数中 Key 的重要性。

  • key 相同,若组件属性有所变化,则 react 只更新组件对应的属性,没有变化则不更新。
  • key 不同,则 react 先销毁该组件(有状态组件的 componentWillUnmount 会执行),然后重新创建该组件(constructor 和 componentWillUnmount 都会执行)
caution

使用 index 作为 key prop。