React 概述
什么是React
React 是一个用于 构建用户界面 的 JavaScript 库。
React的特点
- 组件化编程:某一个页面的任何一个部分都可以是一个组件。
- 用法很广泛:web、VR。。。
React基本使用
安装
安装命令:
1
npm i react react-dom
- react包提供创建元素、组件等功能。
- react-dom包提供DOM相关操作。
使用
-
引入cdn
1 2
<script src="./node_modules/react/umd/react.deelopment.js"></script> <script src="./node_modules/react/umd/react-dom.development.js"></script>
-
创建react元素
1 2 3 4 5 6 7 8 9 10 11 12 13
/** * 创建一个react元素 * para1:元素名称 String * para2:元素属性 object * para3:元素的子节点 String */ const title = React.createElement('h1',null,'hello React'); /** * 渲染react元素 * para1:要渲染的react元素 String * para2:挂载点(html文件中创建的标签) */ ReactDOM.render(title, document.getElementById('root'));
JSX概述
简介
考虑到如下变量声明:
const element = <h1>hello, world</h1>
JSX语法既不是HTML也不是字符串,而是JavaScript的扩展语法
为什么使用?
因为它方便啊!
使用
嵌入表达式
1
2
3
const element = (
<h1>Hello, {该括号内可以放任何js表达式或已定义的变量}</h1>
)
为了便于阅读,会将JSX拆分为多行。同时,我们建议将内容包裹在括号早中,虽然不是强制要求,但是这样可以避免遇到 自动插入分号 的陷阱。
代替表达式
在编译之后,JSX表达式会呗转为普通js函数调用,并对其取值后可以得到JSX对象。(即可以在if和for的代码块钟使用JSX,将JSX赋值给变量)
1
2
3
4
5
6
7
8
9
10
function getUserInfo(user){
if(user){
return (
<h1>Hello, {controduct(user)}!</h1>
)
}
return (
<h1>Hello, Stranger.</h1>
)
}
JSX特定属性
你可以通过使用引号,来将属性值置顶为字符串字面量:
1
2
3
const element = (
<div tabIndex = "0"></div>
)
也可以使用大括号,来在属性之中插入一个JavaScript表达式:
1
2
3
const element = (
<img src = {user.avatarUrl}></img>
)
警告:
引号和大括号不可同时使用
因为 JSX 语法上更接近JavaScript 而不是HTML,所以ReactDOM使用camelCase(小驼峰命名)来定义属性的名称:
例如:JSX里的 class 变成了 className ,而 tabindex 则变为 tabIndex 。
使用JSX指定子元素
加入一个标签里面没有内容,你可以使用 /> 闭合标签,类似于XML语法。
1
const element = <img src = {user.avatarUrl} />
也能包含很多子元素
1
2
3
4
5
6
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);
JSX防止注入攻击
1
2
3
const title = response.potentiallyMaliciousInput;
//直接使用是最安全的
const element = <h1>{title}</h1>
ReactDOM 在渲染所有输入内容之前,默认会进行 转义 。可以确保应用中不会注入那些并非自己明确写的内容。所有的内容在渲染之前都被转换成了字符串。有效防止 XSS 攻击。
JSX表示对象
Babel 会把JSX转译层一个名为 React.createElement() 函数调用。
以下两种示例代码完全等效:(一般用前者)
1
2
3
4
5
const element = (
<h1 className = "greeting">
Hello, world!
</h1>
)
1
2
3
4
5
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
)
渲染(render)
初次渲染
一般index.html里都会有一个根节点,该节点的id为root,称为“根”dom节点
1
<div id='root'></div>
将一个React元素渲染到根DOM节点中,只需把它们一起传入ReactDOM.render():
1
2
3
4
5
6
7
8
/*
* para1:表示要展示的元素
* para2:表示要渲染的位置
**/
const element = (
<h1>Hello, world</h1>
)
ReactDOM.render(element, deocument.getElementById('root'));
更新已渲染的元素(脚手架有新方法)
React 元素是 不可变对象,一旦被创建,就无法更改其子元素和属性,因为它代表了某个特定时刻的UI。
根据已有的知识,更新UI唯一的方式是创建一个全新的元素,并将其传入渲染器(ReactDOM.render())
例子:
1
2
3
4
5
6
7
8
9
10
11
12
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);
组件
分类
函数组件
编写Js函数是定义组件最简单的方式
1
2
3
4
5
function Myintro(props){
return (
<h1>Hello, {props.name}</h1>;
)
}
有效的React函数组件:
- 接收唯一带有数据的 “props”
- 返回一个JSX元素
类组件
1
2
3
4
5
6
7
class Myintro extends React.Component{
render() {
return (
<h1>Hello, {this.props.name}</h1>;
)
}
}
ps:
类组件基于ES6
无论是函数组件还是class组件,组件名的首字母必须大写
React会将以小写字母开头的组件视为原生DOM标签
传值(props)
用户自定义的组件中,JSX所接收的属性(name=”LilMartin”)以及子组件转换为一个对象传递给组件,这个对象就称之为”props”
1
2
3
4
5
6
7
8
9
10
11
//上面的代码渲染出来的结果为:"Hello, LilMartin"
function Myintro(props){
return (
<h1>Hello, {props.name}</h1>;
)
}
const element = <Myintro name = "LilMartin" />; //name就是传入函数的props中的一个属性
ReactDOM.render(
element,
document.getElementById('root')
);
Props 的只读性
无论是函数组件还是类组件,都不能改变自身的props
纯函数(正确)
该函数没有改变人何一个入参的值,被称为 纯函数
function sum (a, b) { return a + b; }
非纯函数
function withdra (account, amount) { account.total -= amount; }
组合组件
一个组件可以在其中加入其他组件,在输出时引用
例如:在List组件中展示多个Myintro组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function List(){
return (
<div>
<Myintro name = "LilMartin" />
<Myintro name = "LilGhost" />
<Myintro name = "DwayneJhonson" />
</div>
);
}
ReactDOM.render(
<List />,
document.getElementById('root')
)
ps:通常来说,一个React应用程序的顶层组件都是APP组件
拆分组件
假如有一个含有一个人全部信息的组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name}
/>
<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>
);
}
该组件用于描述某社交媒体网站上的评论功能,接收 author (访客对象),text (字符串)以及 date (日期)作为props。
该组件因为嵌套关系,难以维护,且很难服用它的各个部分,将其中嵌套的组件抽取出来会更加方便且间接。
-
提取用户头像
1 2 3 4 5 6 7 8
function Avatar(props){ return ( <img className = "Avatar" src = {props.user.avatarUrl} alt = {props.user.name} /> ); }
-
提取用户信息,并在用户名旁边渲染头像
1 2 3 4 5 6 7 8 9 10
function UserInfo(props) { return ( <div className="UserInfo"> <Avatar user={props.user} /> <div className="UserInfo-name"> {props.user.name} </div> </div> ); }
-
单独的组件不需要知道Comment组件内部是怎样渲染的
1 2 3 4 5 6 7 8 9 10 11 12 13
function Comment(props) { return ( <div className="Comment"> <UserInfo user={props.author} /> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); }