前言
上一篇介绍了Reactjs的项目目录结构以及他的工作模式。这篇文章将会通过阅读官方文档,学习Reactjs的语法,逻辑,思想等内容。
文章目录
1、JSX
2、元素
3、组件
一、JSX
1、JSX
前面我们了解到React是通过js来构造html,实际上React就是通过JSX来渲染元素,那么什么是JSX,它跟JS和HTML有什么关联呢?
2、JSX简介
JSX(JavaScript XML)是 js 内定义的一套类 XML 语法,可以解析出目标 js 代码,颠覆传统 js 写法。初接触JSX的语法,可能会让人联想到html模板语言,其实JSX做的工作与HTML所做的工作有一定的相似之处,不用的地方在于,HTML 由浏览器解析,而 JSX 是由 js 解析。
使用JSX可以生成React元素。JSX在被编译后也会转化成js代码执行。React中用不用JSX不是一个硬性条件,只是说使用JSX会有更多的好处。
总而言之,能有JSX做的事,用javascript都能做到。
3、举个栗子(在html文档中创造一个列表)
3.1 JS
var child1 = React.createElement('li', null, '这是列表下的第一条元素');
var child2 = React.createElement('li', null, '这是列表下的第二条元素');
var new_list = React.createElement('ul', { className: 'my-list' }, child1, child2);
3.2 JSX
const new_list = (
<ul className="my-list">
<li>这是列表下第一条元素</li>
<li>这是列表下第一条元素</li>
</ul>
)
Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。上述两种方法实现的效果是一样的。
4、JSX语法
4.1 JSX 的基本语法规则:
1)遇到 HTML 标签(以 <
开头),就用 HTML 规则解析
2)遇到代码块(以 {
开头),就用 JavaScript 规则解析
4.2 JSX 语法示例:
const element = <h1>Hello, world!</h1>;
/* 若一个标签里面没有内容,可以使用 /> 来闭合标签 */
const element = <img src={user.avatarUrl} />;
4.3 表达式嵌套
1、在JSX中,我们还可以使用表达式
/* 通过 { } 接收参数 name */
const name = 'Reactjs';
const element = <h1>Hello, {name}</h1>;
2、在JSX中,我们可以在大括号内放置任何有效的 JavaScript 表达式。这些表达式可以为:
(1)变量名
(2)函数定义表达式
(3)属性访问表达式
(4)函数调用表达式
(5)算数表达式
(6)关系表达式
(7)逻辑表达式
1、放置算数表达式:
const element = <h1>计算10+5的结果:{10+5}</h1>;
2、放置调用函数:
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = <h1>Hello, {formatName(user)}</h1>;
3、JSX作为表达式返回
/* 可以在其他 javascript 中返回 JSX 生成的 DOM 对象 */
function getGreeting(user) {
if (user) {
return <h1>Hello, {formatName(user)}!</h1>;
}
return <h1>Hello, Stranger.</h1>;
}
4.4 命名规则
因为 JSX 语法上更接近 JavaScript 而不是 HTML,所以 React DOM 节点使用 camelCase(小驼峰命名)来定义属性的名称,而不使用 HTML 属性名称的命名约定。
例如,JSX 里的 class 变成了 className
,而 tabindex 则变为 tabIndex
。
4.5 JSX 对象
const element = <h1 className="greeting">Hello, world!</h1>;
上述JSX语法生成的对象结构:
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
这些对象被称为 “React 元素”。它们描述了你希望在屏幕上看到的内容。React 通过读取这些对象,然后使用它们来构建 DOM 以及保持随时更新
二、元素
元素是构成 React 应用的最小砖块。它描述了你在屏幕上想看到的内容。也就是我们日常浏览网页时看到的网页上的图片,文字,表格,列表等等,这些都是由一个或者多个元素组成。
例如:<a>
、<h1>
、<div>
、<span>
、<img>
等
渲染元素也就是画画,将定义的元素在网页中绘制出来,将react渲染成为一个html DOM
1、ReactDOM
我们在使用react开发网页时,会下载两个包,一个是react,一个是react-dom,其中react包是react的核心代码,react-dom则是React剥离出的涉及DOM操作的部分。
react的核心思想是虚拟DOM,react包含了生成虚拟DOM的函数react.createElement,及Component类。当我们自己封装组件时,就需要继承Component类,才能使用生命周期函数等。
react-dom包的核心功能就是把这些虚拟DOM渲染到文档中变成实际DOM。下面学习 ReactDOM 的 API 函数
1.1 render()
render用于将React渲染的虚拟DOM渲染到浏览器DOM,一般在顶层组件使用
(1)语法
render(ReactElement element,DOMElement container,[function callback])
@param:
ReactElement element:待渲染的元素或者组件
DOMElement container:容器节点(已经存在的DOM节点)
[function callback]:回调函数
(2)例子
import ReactDOM from 'react-dom';
/* 渲染组件*/
/* <Example /> 为自定义组件 */
ReactDOM.render(<Example />, document.getElementById('root'));
/* 渲染元素 */
const element = <h1>Hello, world!</h1>;
ReactDOM.render(element, document.getElementById('root'));
(3)一些注意事项
1)ReactDOM.render()
会控制传入容器节点里的内容。当首次调用时,容器节点里的所有 DOM 元素都会被替换,后续的调用则会使用 React 的 DOM 差分算法(DOM diffing algorithm)进行高效的更新。
2)ReactDOM.render()
不会修改容器节点(只会修改容器的子节点)。可以在不覆盖现有子节点的情况下,将组件插入已有的 DOM 节点中。
1.2 findDOMNode()
当我们通过render()方法将组件渲染成DOM以后,避免不了获取该组件的操作,通过findDOMNode()方法可以返回已经完成渲染的组件对应的DOM节点。
(1)语法
ReactDOM.findDOMNode(component)
(2)注意事项
1)findDOMNode 是一个访问底层 DOM 节点的应急方案。在大多数情况下,不推荐使用该方法,因为它会破坏组件的抽象结构
2)大多数情况下,你可以绑定一个 ref 到 DOM 节点上,可以完全避免使用 findDOMNode。
3)findDOMNode 只在已挂载的组件上可用(即,已经放置在 DOM 中的组件)。如果你尝试调用未挂载的组件(例如在一个还未创建的组件上调用 render() 中的 findDOMNode())将会引发异常。
4)findDOMNode 不能用于函数组件。
1.3 unmountComponentAtNode()
从 DOM 中卸载组件,会将其事件处理器(event handlers)和 state 一并清除。如果指定容器上没有对应已挂载的组件,这个函数什么也不会做。如果组件被移除将会返回 true,如果没有组件可被移除将会返回 false。
(1)语法
ReactDOM.unmountComponentAtNode(container)
2、更新元素
React DOM 会将元素和它的子元素与它们之前的状态进行比较,并只会进行必要的更新来使 DOM 达到预期的状态。
计时器例子:
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);
对于上述例子,render每次渲染的时候,都只对h2
进行更新,对于没有改变的元素,render不会对其进行重新渲染。这里面涉及到一个react的差分算法
。
三、组件
首先需要区分组件跟元素的概念,组件是由元素构成的。元素数据结构是普通对象,而组件数据结构是类或纯函数。
就拿建造一座大楼来说,
如果说我们最后使用React构建的网页一座辉煌的高楼。
那么,元素就是砖块,组件就是每一间房间,例如厕所组件、卧室组件、厨房组件,这些组件都是一块一块砖构成,这一座楼房又是有这些房间组件构成。
1、函数组件
定义组件最简单的方式就是编写 JavaScript 函数:
function Hello(props) {
return <h1>Hello, {props.name}</h1>;
}
2、class组件
定义 class 组件,需要继承 React.Component:
class Hello extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
3、渲染组件
回顾之前的元素,发现到目前为止,遇到到React元素都是html DOM 标签,例如
const element = <div />;
const element = <a />;
const element = <img />;
React 元素也可以是用户自定义的组件:
const element = <Hello name="Lisa" />;
上面定义了一个名叫Hello的组件
function Hello(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Hello name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
1、调用 ReactDOM.render() 函数,并传入 <Hello name="Sara" /> 作为参数。
2、React 调用 Hello 组件,并将 {name: 'Lisa'} 作为 props 传入。
3、Hello 组件将 <h1>Hello, Lisa</h1> 元素作为返回值。
4、React DOM 将 DOM 高效地更新为 <h1>Hello, Lisa</h1>
4、自定义组件规则
组件名称必须以大写字母开头
以小写字母开头的元素代表一个 HTML 内置组件,比如 <div>
或者 <span>
会生成相应的字符串 ‘div’ 或者 ‘span’ 传递给React.createElement(作为参数)。大写字母开头的元素则对应着在 JavaScript 引入或自定义的组件,如 <Foo />
会编译为 React.createElement(Foo)。
import React from 'react';
// 错误!组件应该以大写字母开头:
function hello(props) {
// 正确!这种 <div> 的使用是合法的,因为 div 是一个有效的 HTML 标签
return <div>Hello {props.toWhat}</div>;
}
// 正确!组件以大写字母开头了:
function HelloWorld() {
// 错误!React 会认为 <hello /> 是一个 HTML 标签,因为它没有以大写字母开头:
return <hello toWhat="World" />;
}
5、混合组件
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
/* 调用自定义的 Welcome 组件*/
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);