JSX
# JSX
我们在上文中已经很多次的提及了
/** @jsx h */
React.createElement(component,props,...children)
函数调用,譬如我们定义了某个MyButton
:
// 必须要在 JSX 声明文件中引入 React
import React from "react";
<MyButton color="blue" shadowSize={2}>
Click Me
</MyButton>;
会被编译为:
React.createElement(MyButton, { color: "blue", shadowSize: 2 }, "Click Me");
而如果我们直接声明某个
React.createElement("div", { className: "sidebar" }, null);
实际上除了最著名的JSXDOM
与 Mercury JSX
这两个同样的可以将
/** @jsx JSXDOM */
var defaultValue = "Fill me ...";
document.body.appendChild(
<div>
<input type="text" value={defaultValue} />
<button onclick="alert('clicked!');">Click Me!</button>
<ul>
{["un", "deux", "trois"].map(function(number) {
return <li>{number}</li>;
})}
</ul>
</div>
);
这里我们还想讨论另一个问题,为什么需要引入
// JSX
var box = (
<Box>
{shouldShowAnswer(user) ? (
<Answer value={false}>no</Answer>
) : (
<Box.Comment>Text Content</Box.Comment>
)}
</Box>
);
而使用模板字符串的方式如下
// Template Literals
var box = jsx`
<${Box}>
${
shouldShowAnswer(user)
? jsx`<${Answer} value=${false}>no</${Answer}>`
: jsx`
<${Box.Comment}>
Text Content
</${Box.Comment}>
`
}
</${Box}>
`;
其主要缺陷在于因为存在变量的嵌套,需要在作用域中进进出出,很容易造成语法错误,因此还是
JSX 语法
<img>
React.createElement(component,props,...children)
调用,而该函数的第一个参数只允许传入单元素,而不允许传入多元素。
变量使用
- 注释
在<!-- -->
进行注释,不过
render() {
return (
<div>
<!-- This doesn't work! -->
</div>
)
}
我们需要以
{
/* A JSX comment */
}
{
/*
Multi
line
comment
*/
}
- 数组
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{numbers.map(number => (
<ListItem key={number.toString()} value={number} />
))}
</ul>
);
}
- 条件渲染
在
{condition && <span>为真时进行渲染</span> }
如果要进行非操作:
{
condition || <span>为假时进行渲染</span>;
}
我们也可以使用常见的三元操作符进行判断
{
condition ? <span>为真时进行渲染</span> : <span>为假时进行渲染</span>;
}
如果对于较大的代码块,建议是进行换行以提升代码可读性:
{
condition ? <span> 为假时进行渲染 </span> : <span> 为假时进行渲染 </span>;
}
元素属性
style 属性
const divStyle = {
color: "blue",
backgroundImage: "url(" + imgUrl + ")"
};
function HelloWorldComponent() {
return <div style={divStyle}>Hello World!</div>;
}
注意,内联样式并不能自动添加前缀,这也是笔者不太喜欢使用
const divStyle = {
WebkitTransition: "all", // note the capital 'W' here
msTransition: "all" // 'ms' is the only lowercase vendor prefix
};
function ComponentWithTransition() {
return <div style={divStyle}>This should work cross-browser</div>;
}
- className
className
来声明class
属性的。
- htmlFor
因为 for
是htmlFor
作为替代。
Boolean 系列属性
<input type='checkbox' checked={true}>
可以简写为<input type='checkbox' checked>
,而 <input type='checkbox' checked={falsed}>
即不可以省略
- 自定义属性
如果在
<div customProperty='a' />
不过如果要使用data-*
或者 aria-*
形式的属性是支持的。
<div data-attr='attr' />
子元素
- 字符串
我们可以将字符串放置在一对开放与闭合的标签之间,此时所谓的 props.children
即就是字符串类型;譬如:
<MyComponent>Hello World!</MyComponent>
就是合法的MyComponent
中的 props.children
值就是字符串 Hello World!
;另外需要注意的是,
<div>Hello World</div>
<div>
Hello World
</div>
<div>
Hello
World
</div>
<div>
Hello World
</div>
JSX 嵌套我们可以嵌套地使用JSX ,即将某些JSX 元素作为子元素,从而允许我们方便地展示嵌套组件:
<MyContainer>
<MyFirstComponent />
<MySecondComponent />
</MyContainer>
我们可以混合使用字符串与
<div>
Here is a list:
<ul>
<li>Item 1</li> <li>Item 2</li>
</ul>
</div>
某个div
中。
JavaScript 表达式我们可以传入包裹在{}
内的任意JavaScript 表达式作为子元素,譬如下述声明方式渲染的结果是相同的:
<MyComponent>foo</MyComponent>
<MyComponent>{'foo'}</MyComponent>
这种模式常用于渲染
function Item(props) {
return <li>{props.message}</li>;
}
function TodoList() {
const todos = ["finish doc", "submit pr", "nag dan to review"];
return (
<ul>
{todos.map(message => (
<Item key={message} message={message} />
))}
</ul>
);
}
JavaScript 函数正常情况下JSX 中包含的JavaScript 表达式会被解析为字符串、React 元素或者列表;不过props.children
是允许我们传入任意值的,譬如我们可以传入某个函数并且在自定义组件中调用:
// Calls the children callback numTimes to produce a repeated component
function Repeat(props) {
let items = [];
for (let i = 0; i < props.numTimes; i++) {
items.push(props.children(i));
}
return <div>{items}</div>;
}
function ListOfTenThings() {
return (
<Repeat numTimes={10}>
{index => <div key={index}>This is item {index} in the list</div>}
</Repeat>
);
}
- 布尔值与空值
false
,null
,undefined
与true
是有效的子元素,不过它们并不会被渲染,而是直接被忽略,如下的JSX 表达式会被渲染为相同结果:
<div />
<div></div>
<div>{false}</div>
<div>{null}</div>
<div>{undefined}</div>
<div>{true}</div>
避免XSS 注入攻击
最后需要提及的是,
const title = response.potentiallyMaliciousInput;
// This is safe:
const element = <h1>{title}</h1>;
在标准的<script>alert(1)<script/>
这样的可执行代码之后,就存在被©
这样的实体字符时,
function createMarkup() {
return { __html: "First · Second" };
}
function MyComponent() {
return <div dangerouslySetInnerHTML={createMarkup()} />;
}