Rendering Elements
元素是React app里面的最小的一个模块,而且React中的DOM元素都是一些基本的元素,很容易进行创建,虚拟的DOM对象创建起来成本很低。
将一个元素渲染到DOM中
创建一个<div>
标签在HTML文件当中,现在可以通过ReactDOM将这些节点添加到这个标签中,将一个虚拟的React元素渲染到DOM中,可以使用ReactDOM.render()方法
const element = <h1>Hello,world</h1>;
ReactDOM.render(
element,
document.getElementById('root')
);
更新渲染的元素
React元素是不可修改的,一旦你创建了一个元素,就不能够修改这个元素的子元素和属性,现在只可以通过添加一个新的元素来更新UI,然后将这个元素传递给ReactDOM.render()
方法。
function tick() {
const element = (
<div>
<h1>Hello, world</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('root')
);
}
setInterval(tick, 1000);
React只是在需要的时候才会刷新DOM
ReactDOM会比较元素包括子元素与之前的比较,只有必须要更新DOM的时候,才会去刷新DOM状态。不会随便更新DOM。
即使在上面的代码中修改了许多次的DOM元素,但是真正渲染的DOM元素只有其中的h2元素的文本节点。
Components and Props
组件可以用来将UI分割为一个个模块,可以复用的部分,并且这些部分都是隔离开的。从概念上来将,组件类似于JavaScript的函数,可以接收任意输入来返回一个React元素来描述需要渲染的结果。
函数式和类组件
最简单的定义一个组件的方法是写一个JavaScript函数:
function Welcome (props) {
return <h1>Hello, {props,name}</h1>;
}
这个函数是一个简单可以用的React组件,接收一个参数props,并且返回一个React元素,这个组件是函数式的,因为它用了JavaScript的函数语法。
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
渲染一个组件
之前的React元素都是代表着一个DOM元素,其实也可以建立一个用户自定义的组件,当React发现了一个用户自定义组件的时候,传递给了JSX一个属性给组件一个独立的对象。
//DOM元素
const DOMelement = <div />
//自定义元素
const UserDefineElement = <Welcome name="Sara" />
function Welcome(props) {
return <h1>Hello, {props.name}</h1>
}
const element = <Welcome name="Sara" />
ReactDOM.render(
element,
document.getElementById('root')
);
组件的名字都是以大写形式开头的。
组件构成
组件可以引用其他组件作为他的输出,这让我们可以使用相同的组件,传入不同的信息,比如一个button,一个dialog,一个screen。比如可以创建一个App组件,通过多次渲染Welcome实现。
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
)
}
组件必须返回一个单独的根节点,所以上面代码中的App函数返回的节点是被一个div元素包裹的。
提取组件
不要害怕将一个组件分隔为多个小的组件。
let formatDate = function(date) {
return date.toLocaleDateString();
}
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img src={props.author.avatarUrl} alt={props.author.name} className="Avatar"/>
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
let props = {
author: {
name: "Lucas",
avatarUrl: "www.baidu.com"
},
text: "This is a piece of shit.",
date: new Date()
}
console.log(props);
const element = <Comment author={props.date} text={props.text} date={props.date} />
ReactDOM.render(
element,
document.getElementById("root")
);
上面的代码中,接收了author,text,date三个属性作为参数,但是这个组件因为其复杂性很难被reuse,所以可以从中提取出一些组件,首先提取出Avatar,建议从组件自己的角度来命名属性,而不要从上下文中命名。
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<Avatar user={props.author}></Avatar> //这是将上面组件的一个部分从新构成一个组件
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
再从中抽取UserInfo部分来可以构建多个UserCondition
function UserInfo(props){
return (
<div className="UserInfo">
<Avatar user={props.user} />
<div className="UserInfo-name">
{props.user.name}
</div>
</div>
);
}
根据上面的UserInfo组件,可以构建一个简单的Comment组件。
function Comment(props) {
return (
<div className="Comment">
<UserInfo user={props.author}></UserInfo>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formateDate(props.date)}
</div>
</div>
);
}
只读属性
无论是通过函数或者类声明了一个组件,都不能够修改组件自己的自有属性。比如函数:
function sum(a, b){
return a+b;
}
这个函数被称作纯净的函数,这个函数不会试图去修改其输入的参数,并且总是返回一个与输入类似的输出
相反,下面这个函数是不纯净的,因为它修改了自己的输入:
function withdraw(account, amount){
account.total -= amount;
}
React是比较灵活的,但是其有一个很严格的规则,也就是:
所有的React组件都要像一个纯净函数一样,不去修改输入的参数。