React的渲染
在react的官网上,最开始说的就是关于react的声明式渲染,而这一部分主要体现在react的渲染方式上面,react很灵活的把渲染内容交由开发者来管理,就像正常书写HTML一样,
const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;
ReactDOM.render(
element,
document.getElementById('root')
);
上面这段代码,大部分是js的语法,但是多了一些js以外的内容,这就是JSX【JavaScript XML】,是一个 JavaScript 的语法扩展。我们建议在 React 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。JSX 可能会使人联想到模版语言,但它具有 JavaScript 的全部功能。
React 认为渲染逻辑本质上与其他 UI 逻辑内在耦合,比如,在 UI 中需要绑定处理事件、在某些时刻状态发生变化时需要通知到 UI,以及需要在 UI 中展示准备好的数据。React 并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式,而是通过将二者共同存放在称之为“组件”的松散耦合单元之中,来实现关注点分离。
综上:这种混合UI[html元素]和js语法的部分就是JSX
JSX的学习使用
我们先来看一段简单的代码,这是一个很简单的JSX表达式:
const element = <h1>Hello, {name}</h1>;
JSX的变量可以是UI和JS语法的结合体,并使用在任何JSX代码中:
function getGreeting(user) {
if (user) {
return <h1>Hello, {formatName(user)}!</h1>;
}
return <h1>Hello, Stranger.</h1>;
}
// 复杂一点的使用
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
JSX的特性
jsx的自定义组件名字必须是大写字母开头, 由于 JSX 会编译为 React.createElement 调用形式,所以 React 库也必须包含在 JSX 代码作用域内。
就像我们看到的,JSX包括了UI部分的HTML元素,那么就可以添加各种属性,而JSX支持两种引入属性的方式,
- 字符串字面量,仅支持字符串:
const element = <div tabIndex="0"></div>;
- JavaScript表达式【赋值、条件if、for代码块都不算表达式】:
const element = <img src={user.avatarUrl}></img>;
因为 JSX 语法上更接近 JavaScript 而不是 HTML,所以 React DOM 使用 camelCase(小驼峰命名)来定义属性的名称,而不使用 HTML 属性名称的命名约定。例如,JSX 里的 class 变成了 className,而 tabindex 则变为 tabIndex。
JSX还可以防止注入攻击,React DOM 在渲染所有输入内容之前,默认会进行转义。它可以确保在你的应用中,永远不会注入那些并非自己明确编写的内容。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS(cross-site-scripting, 跨站脚本)攻击。
jsx还支持点语法:
// 由于 JSX 会编译为 React.createElement 调用形式,所以 React 库也必须包含在 JSX 代码作用域内。
import React from 'react';
const MyComponents = {
DatePicker: function DatePicker(props) {
return <div>Imagine a {props.color} datepicker here.</div>;
}
}
function BlueDatePicker() {
return <MyComponents.DatePicker color="blue" />;
}
jsx通用支持运行时来选择渲染的组件写法
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// 正确!JSX 类型可以是大写字母开头的变量。
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
}
jsx允许开发者把包裹在 {} 中的 JavaScript 表达式作为一个 prop 传递给 JSX 元素。if 语句以及 for 循环不是 JavaScript 表达式,所以不能在 JSX 中直接使用。但是,你可以用在 JSX 以外的代码中;Props 默认值为 “True”
function NumberDescriber(props) {
let description;
if (props.number % 2 == 0) {
description = <strong>even</strong>;
} else {
description = <i>odd</i>;
}
return <div>{props.number} is an {description} number</div>;
}
// 一下两行等价
<MyTextBox autocomplete />
<MyTextBox autocomplete={true} />
jsx同样支持属性展开
const Button = props => {
const { kind, ...other } = props;
const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
return <button className={className} {...other} />;
};
const App = () => {
return (
<div>
<Button kind="primary" onClick={() => console.log("clicked!")}>
Hello World!
</Button>
</div>
);
};
jsx子元素的类型可以使很多种:
字符串字面量:JSX 会移除行首尾的空格以及空行。与标签相邻的空行均会被删除,文本字符串之间的新行会被压缩为一个空格。
// 一下几行是一样的 <div>Hello World</div> <div> Hello World </div> <div> Hello World </div> <div> Hello World </div>
jsx元素:单个元素,混合元素,或者存储在数组中的一组元素
<MyContainer> <MyFirstComponent /> <MySecondComponent /> </MyContainer> <div> Here is a list: <ul> <li>Item 1</li> <li>Item 2</li> </ul> </div> render() { // 不需要用额外的元素包裹列表元素! return [ // 不要忘记设置 key :) <li key="A">First item</li>, <li key="B">Second item</li>, <li key="C">Third item</li>, ]; }
- javascript表达式/函数:
{}
大把括号包围的,可以使开发者结合使用的长比较多。
jsx对于一下额子元素:false, null, undefined, and true处理,虽然都是合法的子元素。但它们并不会被渲染。但是其他的伪真数值会被渲染: 0
JSX的本质
从本质上来讲,JSX最终是要表示对象,JSX的语法是名为 React.createElement()
函数的语法糖,以下两种示例代码完全等效:
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
const element = React.createElement(
'h1', // tagname
{className: 'greeting'}, // props
'Hello, world!' // 子元素 children
);
React.createElement()
会预先执行一些检查,以帮助你编写无错代码,但实际上它创建了一个这样的对象:
// 注意:这是简化过的结构
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
这些对象被称为 “React 元素”。它们描述了你希望在屏幕上看到的内容。React 通过读取这些对象,然后使用它们来构建 DOM 以及保持随时更新。
React渲染
使用JSX就是能够方便开发者书写想要的界面,而这些内容最好是要渲染成真正的HTML展示的,元素是构成 React 应用的最小砖块。元素描述了你在屏幕上想看到的内容。const element = <h1>Hello, world</h1>;
与浏览器的 DOM 元素不同,React 元素是创建开销极小的普通对象【就是上文提到的JSX对象本质】。React DOM 会负责更新 DOM 来与 React 元素保持一致。
之前有提到,使用React就是把HTML中的某个节点完全交个React来管理和渲染更新,想要将一个 React 元素渲染到根 DOM 节点中,只需把它们一起传入 ReactDOM.render(),
// HTML中交给React管理的跟节点 一般是body元素下的唯一节点
<div id="root"></div>
// react 部分
const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
渲染完成之后,我们知道很多时候通过一些交互,我们需要完成更新,我们可以通过修改JSX元素,重新执行ReactDOM.render, ReactDOM会将元素和它的子元素与它们之前的状态进行比较,并只会进行必要的更新来使 DOM 达到预期的状态。这样就可以提高性能,避免不必要的渲染。
那么除了频繁的调用ReactDOM.render外,其实React还提供了方法让开发者自己定位需要修改的内容,只要更新对于元素/组件的props和state就可以,后面将会讲解props和state的具体内容。