什么是JSX
JSX==JavaScriptXML,是React的核心组成部分,它使用XML标记的方式去直接声明界面,界面组件之间可以互相嵌套。
JSX 可以理解为在JS中编写与XML类型的语言,但它与XML在本质上有所不同。它的目的不是要在浏览器或者引擎中发现,也不是把其加入ECMAScript标准。它的目的是通过各种编译器讲这些标记编译成标准的js语言。
JSX 语法
JSX本身就和XML语法相似,可以定义属性以及子元素。唯一特殊的是可以用大括号来加入Javascript表达式,例如
class HelloMessage extends React.Component {
render() {
return <div>Hello {this.props.name}</div>;
}
}
ReactDOM.render(
<HelloMessage name="Jerry"/>,
document.getElementById('root')
);
JSX扩展属性
不要改变props
如果提前就知道了组件的属性的化,写起来很容易例如component组件有两个动态的属性foo和bar:
var component = <Component foo={x} bar={y} />;
而实际上,有些属性可能是后续添加的,我们没办法一开始就确定,我们可能会写出下面不好的代码:
var component = <Component />;
component.props.foo = x; // bad
component.props.bar = y; // also bad
这样写是错误的,因为我们手动直接添加的属性React后续没办法检查到属性类型错误,也就是说,当我们手动添加的属性发生类型错误时,在控制台是看不到错误信息的。
在React的设定中,初始化完props后,props是不可变的。改变props会引起无法想象的后果。
扩展属性
为了解决这个问题,React引入了属性扩展
var props = {};
props.foo = x;
props.bar = y;
var component = <Component {...props} />;
当需要拓展我们的属性的时候,定义个一个属性对象,并通过{...props}的方式引入,React会帮我们拷贝到组件的props属性中。重要的是—这个过程是由React操控的,不是手动添赋值的属性。
需要覆盖的时候可以这样写:
var props = { foo: 'default' };
var component = <Component {...props} foo={'override'} />;
JSX陷阱
style属性
在React中写行内样式时,要这样写,不能采用引号的书写方式,因为JSX的属性是以对象的方式存在的。
ReactDOM.render(
<div style={{color:'red'}}>
xxxxx
</div>,
document.getElementById('root')
);
HTML转义
var content='<strong>content</strong>'; ReactDOM.render( <div>{content}</div>, document.getElementById('root') );
结果页面直接输出内容了:
<strong>content</strong>React默认会进行HTML的转义,避免XSS攻击,如果要不转义,可以这么写:
var content='<strong>content</strong>'; ReactDOM.render( <div dangerouslySetInnerHTML={{__html: content}}></div>, document.getElementById('root') );
页面输出:
content
自定义HTML属性
如果在编写React过程中使用了自定义属性,React不会渲染的; 如果需要使用自定义属性,要加 data-
的前缀。
布尔值、Null和Undefined被忽略
false、null、undefined和true都是有效的子代,但它们不会直接被渲染
React 必须声明
由于 JSX 编译后会调用 React.createElement
方法,所以在你的 JSX 代码中必须首先声明React
变量。
JSX编译
<div className="red">Children Text</div>;
<MyCounter count={3 + 5} />;
// Here, we set the "scores" attribute below to a JavaScript object.
var gameScores = {
player1: 2,
player2: 5
};
<DashboardUnit data-index="2">
<h1>Scores</h1>
<Scoreboard className="results" scores={gameScores} />
</DashboardUnit>;
Babel在线编译:https://babeljs.io/repl/
HTML 标签对比 React 组件
React 可以渲染 HTML 标签 (strings) 或 React 组件 (classes)。 要渲染 HTML 标签,只需在 JSX 里使用小写字母的标签名。
var myDivElement = <div className="foo" />;
ReactDOM.render(
myDivElement ,
document.getElementById('root')
);
要渲染 React 组件,只需创建一个大写字母开头的本地变量。
function UserGreeting(props) {
return <h1>Welcome back!</h1>;
}
var myElement = <UserGreeting someProperty={true} />;
ReactDOM.render(
myElement ,
document.getElementById('root')
);
React 的 JSX 使用大、小写的约定来区分本地组件的类和 HTML 标签。
注意: 由于 JSX 就是 JavaScript,一些标识符像 class 和 for 不建议作为 XML 属性名。作为替代,React DOM 使用 className 和 htmlFor 来做对应的属性。
怎样指定 React 元素类型? JSX的标签名决定React元素的类型。
JSX转换过程
那么形如HTML标签实际上却是对象的React组件是如何构成的呢? 查看React源码如下:
var React = {
Children: {
map: mapChildren,
forEach: forEachChildren,
count: countChildren,
toArray: toArray,
only: onlyChild
},
Component: Component,
PureComponent: PureComponent,
unstable_AsyncComponent: AsyncComponent,
Fragment: REACT_FRAGMENT_TYPE,
createElement: createElementWithValidation,
cloneElement: cloneElementWithValidation,
createFactory: createFactoryWithValidation,
isValidElement: isValidElement,
version: ReactVersion,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
ReactCurrentOwner: ReactCurrentOwner,
// Used by renderers to avoid bundling object-assign twice in UMD bundles:
assign: _assign
}
};
module.exports = react;
在 import React from 'react'
时,引入的就是源码中提供的React对象。 在extends Component时,继承了Component类
。这里需要说明两点:
- 这里是列表文本源码中明明使用的
module.exports
而不是export default
,为什么还能够成功引入呢?
其实这是babel解析器的功劳。它令(ES6)import === (CommonJS)require。而在typescript中,需要严格的export default声明,故在typescript下就不能使用import React from 'react'
了。
- 我们可以写extends Component也可以写extends React.Component,这两者是否存在区别呢? 答案是否定的。因为
Component是React.Component的引用
。 也就是说Component === React.Component
,在实际项目中写哪个都可以。