什么是 React ?
React是一个声明式的,高效的,并且灵活的用于构建用户界面的 JavaScript 库
一个最简单的React例子
ReactDom.render(
<h1>Hello World</h1>,
document.getElementById('root')
)
ReactDom.render
接受两个参数,第一个是要被插入的内容,第二个是插入到DOM或者说index.html
的位置
一个与Html对比的简单组件
如下是一个 React 组件
class ShoppingList extends React.Componnet {
render() {
return (
<div className="shopping-list">
<h1>Shoping List for {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatApp</li>
<li>Oculus</li>
</ul>
</div>
)
}
}
// Example usage: <ShoppingList name="Mark" />
在这里,ShoppingList是一个 React组件类,或 React组件类型。组件接受参数,称为属性 props
, 并通过 render
方法返回一个现实的视图层次结构。
render
方法返回您要渲染的内容描述,然后React接受该描述并将其渲染到屏幕上,特别是,render
返回一个React 元素,这是一个渲染内容的轻量级的描述。大多数
React 开发人员使用 JSX
语法,也是上述案例写到的语法。
JSX
语法的转换规则为: <div />
语法在构建是被转换为 React.createElement('div')
。因此,上面的例子等价于:
return React.createElement('div', {className: 'shopping-list'},
React.createElement('h1', /* h1 children ... */),
React.createElement('ul', /* ul children ... */)
);
既然 JSX
在 React 开发者中这么流行,那 JSX
又是什么呢?
JSX 语法
JSX
它是 Javascript
的一种拓展语法,能够让你的 Javascript
中和正常描述 HTML一样编写 HTML。
你可以用 花括号
将任意 Javascript
表达式嵌入到 JSX
中。例如:表达式 1 + 2
, 变量 user.firstName
, 和函数 formatName(User)
等都可以嵌入使用
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'harper',
lastName: 'Perez'
}
const element = {
<h1> Hello, {formatName(user)}! </h1>
}
ReactDOM.render (
element,
document.getElementById('root')
)
请注意,为了方便阅读开发者们常将 JSX
分割成多行包裹起来,因为这可以避免分号自动插入的陷阱,如
{ 1
2 } 3
// is transformed to
{ 1
;2 ;} 3;
JSX 也是一个表达式
编译之后, JSX
表达式也就成了一个常规的 javascript
对象
也正因为如此,我们可以在 if
语句或这是 for
循环语句中使用 JSX
,用它给变量赋值,当做参数接受,或者作为函数的返回值
function getGreeting(user) {
if (user) {
return <h1>Hello. {formatName(User}</h1>;
}
return <h1>Hello, Stranger</h1>
}
用 JSX 指定属性值
你可以用花括号嵌入一个 JavaScript 表达式作为属性值
// 用引号形式
const element = <div tableIndex="0"></div>;
// 用表达式,并且表达式用花括号包裹
const element = <img src={user.avatarUrl}></img>;
用 JSX 指定子元素
如果是空标签,可以直接用 />
闭合
const element = <img src={user.avatarUrl} />
如果包含子标签:
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
比起
HTML
,JSX
更接近于Javascript
,所以React DOM
规范使用驼峰(camelCase)属性命名约定,而不是HTML属性名称,当然,html的部分属性名称也作为保留字,不可使用,例如class
;
因此,class
在 JSX 中 变为className
,tableindex
变为tableIndex
。
元素渲染到DOM
正常情况下,你的 index.html
文件下会有这么一个div
<div id='root'></div>
这个root
DOM 节点挂在所有React DOM的位置。正常情况下,对于一个React单页面应用构建,只需要一个单独的根DOM节点即可。但如果要把React整合到现有的APP中,则可能会使用到多个DOM节点。
React利用render
方法将React元素渲染到DOM上,一旦元素被渲染到页面了之后,就不能在修改器子元素或任何元素的属性,就像电影里的一帧,在某以特定的时间点的UI效果,那元素的更新呢?没错,就是重新 render
function tick() {
cosnt element = {
<div>
<h1>Hello, world</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
};
ReactDom.render (
element,
document.getElementById('root')
)
}
setInterval(tick, 1000);
实际上,大多数 React 应用只会调用一次ReactDom.render(),而实现组件更新的办法就是将代码封装在有状态的组件中。
React 只更新必须更新的部分
这正是 React 的强大之处。React DOM 会将元素及其子元素与之前版本逐一对比,并只对有必要更新的 DOM 进行更新, 以达到 DOM 所需的状态。
开发过程中,更应该每个时间点UI的表现, 而不是关注随着时间不断更新UI的状态, 可以减少很多奇怪的 bug
组件和属性
组件 components
和属性 props
,其中,属性是单词 property
的代码简写。
定义组件的两种办法
定义组件有两种方式
- 函数式组件定义
- 类组件定义
最简单的定义组件的方法就是写一个Javascript
函数
function Welcome(props) {
return <h1>Hello, props.name</h1>
}
这就是一个有效的组件,它接首了一个 props
参数,并返回了一个React元素,这是一个函数式组件,表面上看,他就是一个 Javascript
函数。
类组件的定义则依赖ES6 的 class
来定义,下面这种定义方法和上方是等效的;
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
渲染一个组件
// DOM标签作为组件
const element = <div />;
// React 元素作为组件
const element = <Welcome name="Sara" />;
当React 遇到一个代表用户定义组件的元素时,它将 JSX
属性以一个单独对象即props对象
的形式传递给相应的组件,例如
function Welcome(props) {
return <h1>Hello, {props.mname] </h1>;
}
const element = <Wlecome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
)
【理解】
- 调用
ReactDOM.render()
方法并向其传入了<Welcome name="Sara" />
元素 - Raect 调用
Welcome
组件,并向其传入了{name: ‘Sara’}
作为props对象
Welcome
组件返回<h1>Hello, Sara</h1>
- React DOM 迅速更新 DOM,使其显示为
<h1>Hello, Sara</h1>
组件名称总是以大写字母开始, 如本例子中
<Welcome />
, 而不是<welcome />
构成组件
既然组件是单独的一个React元素,那他能单独工作,因此我们能在一个React 元素中多次引用到相同的组件, 举个例子:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>
}
function App() {
return (
<Welcome name="Sara" />
<Welcome name="Lucy" />
<Welcome name="Edite" />
)
}
ReactDOM.render(
<App />,
document.getElementBuId('root')
)
通常情况下, React apps 都有一个单独的顶层的 App
组件。如果是在已有的应用中整合React,也需要由下至上的从小的组件开始逐步整合到视图顶层的组件中。
组件必须返回一个单独的根元素,这就是为什么我们要添加一个
<div>
来包裹所有的<Welcome />
元素的原因
提取组件
对于一个React 元素,如果其中含有可复用或可能会重复使用的内容,不要害怕把它单拿出来多个更小的组件。
提取组件可能看起来是一个繁琐的工作,但是在大型的 App
中可以回报给我们的是大量的可复用组件。一个好的经验准则是如果你 UI 的一部分需要用多次 (Button
,Panel
,Avatar
),或者本身足够复杂(App
,FeedStory
,Comment
),最好的做法是使其成为可复用组件。
Props 是只读的
无论你用函数或类的方法来声明组件,
虽然 React 很灵活,但是它有一条严格的规则:**所有 React 组件都必须是纯函数,并禁止修改其自身 props **。所谓的纯函数就是:传入函数参数不会在函数执行过程中发生改变,比如自增操作 a++
。
如果props
是只读的,那传递给子元素(子组件)的参数岂不是不能修改了?那子元素如何与父元素做交互呢?React还给我们提供了状态属性 state
供我们在子组件内部修改值