React 入门
作者:互联网
React 背景知识
React 是一个用于构建用户界面的 JavaScript 库,主要用于构建 UI,而不是一个 MVC 框架,但可以使用 React 作为 MVC 架构的 View 层轻易的在已有项目中使用,它是一个用于构建用户界面的 JavaScript 库,起源于 Facebook 的内部项目,用来架设 Instagram 的网站,于 2013 年 5 月开源。
React 特点
-
1.声明式设计 −React采用声明范式,可以轻松描述应用。
-
2.高效 −React通过对DOM的模拟,最大限度地减少与DOM的交互。
-
3.灵活 −React可以与已知的库或框架很好地配合。
-
4.JSX − JSX 是 JavaScript 语法的扩展。React 开发不一定使用 JSX ,但我们建议使用它。
-
5.组件 − 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。
-
6.单向响应的数据流 − React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。
环境准备
方式一:在浏览器中编写代码
- 直接在浏览器选项卡中使用
codepen
编写
方法二:直接使用 Staticfile CDN
的 React CDN
库
- 直接使用 Staticfile CDN 的 React CDN 库,地址如下:
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
- 官方提供的 CDN 地址:
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- 生产环境中不建议使用 -->
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
- 使用实例如下,直接打开index.html页面会输出
Hello, world!
:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello React!</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
</script>
</body>
</html>
方式三:搭建本地开发环境,通过 npm 使用 React
-
使用 create-react-app 快速构建 React 开发环境
$ cnpm install -g create-react-app $ create-react-app my-app $ cd my-app/ $ npm start // 运行本地服务
在浏览器中打开 http://localhost:3000/
就能看到运行结果。
- 项目的目录结构如下:
my-app/
README.md
node_modules/
package.json
.gitignore
public/
favicon.ico
index.html
manifest.json
src/
App.css
App.js
App.test.js
index.css
index.js
logo.svg
manifest.json
指定了开始页面 index.html
,一切的开始都从这里开始,所以这个是代码执行的源头。
React 元素渲染
将元素渲染到 DOM 中
首先我们在一个 HTML 页面中添加一个 id=“example” 的
,如下:<div id="example"></div>
React 开发应用时一般只会定义一个根节点。
要将React元素渲染到根DOM节点中,我们通过把它们都传递给 ReactDOM.render() 的方法来将其渲染到页面上:
const element = <h1>Hello, world!</h1>;
ReactDOM.render(
element,
document.getElementById('example')
);
更新元素渲染
React 元素都是不可变的。当元素被创建之后,你是无法改变其内容或属性的。
目前更新界面的唯一办法是创建一个新的元素,然后将它传入 ReactDOM.render() 方法,比如下面这个定时器:
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>现在是 {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('example')
);
}
setInterval(tick, 1000);
ReactDOM.render调用函数及参数传递
- ReactDOM.render内调用 已有函数与常规的JS有很大的区别:
- 函数引用直接包含在
</>
中,而不是()
- 多个参数是以
key、value
时直接传递的,而不是对象格式的date数据 - 示例如下:
- 函数引用直接包含在
ReactDOM.render(
< functionname property1 = {property1_value} property2 = {property2_value} />,
document.getElementById('example')
);
以下实例用一个函数来表示前面的定时器封装:
function Clock(props){
return (
<div id={props.id}>
<h1>Hello, {props.name} ~</h1>
<h2>现在是北京时间 {props.date.toLocaleTimeString()}</h2>
</div>
)
}
function tick() {
ReactDOM.render(
< Clock date={new Date()} name={'world'} id={'world'}/>,
document.getElementById('example')
);
}
setInterval(tick, 1000);
值得注意的是 React DOM 首先会比较元素内容先后的不同,而在渲染过程中只会更新改变了的部分。
创建React.Component 的 ES6 类
需要注意的是在 render()
方法中,需要使用this.props
替换 props
,示例:
class Clock extends React.Component{
render(){
return(
<div id={this.props.id}>
<h1>Hello, {this.props.name} ~</h1>
<h2>现在是北京时间 {this.props.date.toLocaleTimeString()}</h2>
</div>
)
}
}
function tick() {
ReactDOM.render(
< Clock date={new Date()} name='world' id='world'/>,
{/* new Date() 这样的value,需要使用花括号来包含,仅字符串的值则不需要 */}
document.getElementById('example')
);
}
setInterval(tick, 1000);
React JSX
js和jsx的区别
既然这里提到了jsx,那就顺便了解一下两者的区别:
- JS:即
JavaScript
,一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于浏览器客户端的脚本语言。 - JSX: 即
JavaScript XML
——一种在React组建内部构建标签的类XML语法。(增强React程序组件的可读性)。Javascript和XML结合的一种格式。React发明了JSX,利用HTML语法来创建虚拟DOM。当遇到<,JSX就当HTML解析,遇到{就当JavaScript解析。
使用 jsx
React 实例
ReactDOM.render(
<div>
<h1>React JSX</h1>
<h2>欢迎学习 React jsx</h2>
<p data-myattribute = "somevalue">这是一个很不错的 JavaScript 库!</p>
</div>,
document.getElementById('example')
);
jsx独立文件
- 创建jsx独立文件:例如我们创建一个 helloworld_react.js 文件,代码如下:
ReactDOM.render(
<h1>hello, world</h1>,
document.getElementById('example')
)
- 然后在 HTML 文件中引入该 JS 文件(注意:script type 为
text/babel
):
<body>
<div id="example"></div>
<script type="text/babel" src="helloworld_react.js"></script>
</body>
JavaScript 表达式
- 在 JSX 中使用 JavaScript 表达式。表达式写在花括号 {} 中:
ReactDOM.render(
<div>
<h1>{1+1}</h1>
</div>
,
document.getElementById('example')
);
- 条件判断语句:在 JSX 中不能使用 if else 语句,但可以使用 conditional (三元运算) 表达式来替代
ReactDOM.render(
<div>
<h1>{i == 1 ? 'True!' : 'False'}</h1>
</div>
,
document.getElementById('example')
)
样式
React 推荐使用内联样式。我们可以使用 camelCase 小驼峰
语法来设置内联样式. React 会在指定元素数字后自动添加 px
,如font-size
要写成fontSize
:
let myStyle = {
fontSize: 100,
color: '#FF0000'
};
ReactDOM.render(
<h1 style={myStyle}>hello, world {1+1}</h1>,
document.getElementById('example')
)
注释
注释需要 写在花括号{} 中,实例如下:
ReactDOM.render(
<h1>
hello, world {1+1}
{/*这是注释部分*/}
</h1>,
document.getElementById('example')
)
数组
JSX 允许在模板中插入数组,数组会自动展开所有成员:
let arr = [
<h1>React教程</h1>,
<h2>学的不仅是React,学的是方法。</h2>,
];
ReactDOM.render(
<div>{arr}</div>,
document.getElementById('example')
)
React 组件
实例解析:
function HelloMessage(props) {
return <h1 className={props.class}>Hello {props.name}!</h1>;
}
const element = <HelloMessage class='testClass' name="Runoob"/>;
ReactDOM.render(
element,
document.getElementById('example')
);
注意:
- 原生 HTML 元素名以小写字母开头,而
自定义的 React 类名以大写字母开头
,比如 HelloMessage 不能写成 helloMessage。除此之外还需要注意组件类只能包含一个顶层标签,否则也会报错。 - 在添加属性时, class 属性需要写成
className
,for 属性需要写成htmlFor
,这是因为 class 和 for 是 JavaScript 的保留字。
复合组件
直接看例子吧:
function Name(props){
return <h1>网站名称:{props.name}</h1>
}
function Url(props){
return <h1>网站地址:{props.url}</h1>
}
function Nickname(props){
return <h1>网站小名:{props.nickname}</h1>
}
function App(){
return (
<div>
<Name name='React 复合组件学习'/>
<Url url='http://www.runoob.com'/>
<Nickname nickname={'React'}/>
</div>
)
}
ReactDOM.render(
<App/>,
document.getElementById('example')
);
React State(状态)
React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。
React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
将生命周期方法添加到类中
在具有许多组件的应用程序中,在销毁时释放组件所占用的资源非常重要。
- 挂载:每当 Clock 组件第一次加载到 DOM 中的时候,我们都想生成定时器,这在 React 中被称为
挂载
。 - 卸载:同样,每当 Clock 生成的这个 DOM 被移除的时候,我们也会想要清除定时器,这在 React 中被称为
卸载
。
我们可以在组件类上声明特殊的方法,当组件挂载或卸载时,来运行一些代码:
class Clock extends React.Component {
constructor(props) {
super(props)
this.state = {date: new Date()}
}
componentDidMount(){
let _this = this;
this.timerID = setInterval(function (){
_this.tick()
}, 1000)
}
componentWillUnmount() {
clearInterval(this.timerID)
}
tick(){
this.setState({
date: new Date()
})
}
render(){
return(
<div>
<h1>Hello, world!</h1>
<h2>现在是北京时间:{this.state.date.toLocaleTimeString()}</h2>
</div>
)
}
}
ReactDOM.render(
<Clock />,
document.getElementById('example')
);
实例解析:
componentDidMount()
与componentWillUnmount()
方法被称作生命周期钩子。- 在组件输出到
DOM
后会执行componentDidMount()
钩子,我们就可以在这个钩子上设置一个定时器。 - 通过调用
setState()
,React 知道状态已经改变,并再次调用render()
方法来确定屏幕上应当显示什么。 这一次,render()
方法中的this.state.date
将不同,所以渲染输出将包含更新的时间,并相应地更新 DOM。 this.timerID
为定时器的ID
,我们可以在componentWillUnmount()
钩子中卸载定时器。
数据自顶向下流动
父组件或子组件都不能知道某个组件是有状态还是无状态,并且它们不应该关心某组件是被定义为一个函数还是一个类。
这就是为什么状态通常被称为局部或封装。 除了拥有并设置它的组件外,其它组件不可访问。
以下实例中 FormattedDate 组件将在其属性中接收到 date 值,并且不知道它是来自 Clock 状态、还是来自 Clock 的属性、亦或手工输入:
function FormattedDate(props){
return <h2>现在是北京时间:{props.date.toLocaleTimeString()}</h2>
}
class Clock extends React.Component {
constructor(props) {
super(props)
this.state = {date: new Date()}
}
componentDidMount(){
let _this = this;
this.timerID = setInterval(function (){
_this.tick()
}, 1000)
}
componentWillUnmount() {
clearInterval(this.timerID)
}
tick(){
this.setState({
date: new Date()
})
}
render(){
return(
<div>
<h1>Hello, world!</h1>
<FormattedDate date={this.state.date}/>
</div>
)
}
}
function App(){
return(
<div>
<Clock />
<Clock />
<Clock />
</div>
)
}
ReactDOM.render(
<App />,
document.getElementById('example')
);
这里我还没有完全理解它的含义!
React Props
state
和 props
主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。
基本用法
前面的示例中都已经涉及到Props的使用,这里不再举例,只再提示一点普通类和ES6 class使用上的差别:
- 普通的类:使用
props.name
方式访问属性 - ES6 类:使用
this.props.name
方式访问属性
State 和 Props
例:在父组件中设置 state, 并通过在子组件上使用 props 将其传递到子组件上。在 render 函数中, 我们设置 name 和 site 来获取父组件传递过来的数据
class Book extends React.Component{
constructor(props) {
super(props)
this.state = {
name: 'react',
time: '2013年5月',
}
}
render() {
return (
<div>
<Name name={this.state.name}/>
<Time time={this.state.time}/>
</div>
)
}
}
class Name extends React.Component {
render(){
return(
<h1>Book name: {this.props.name}</h1>
)
}
}
class Time extends React.Component {
render(){
return(
<h1>Book create time: {this.props.time}</h1>
)
}
}
ReactDOM.render(
<Book />,
document.getElementById('example')
)
Props 验证
React.PropTypes 在 React v15.5 版本后已经移到了 prop-types 库。 React v15.5 版本以上使用时需要引入:
<script src="https://cdn.staticfile.org/prop-types/15.6.1/prop-types.js"></script>
Props 验证使用 propTypes
,它可以保证我们的应用组件被正确使用,React.PropTypes
提供很多验证器 (validator) 来验证传入数据是否有效。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。
React 16.4 实例:
var title = "react learner";
class MyTitle extends React.Component {
render() {
return (
<h1>Hello, {this.props.title}</h1>
);
}
}
MyTitle.propTypes = {
title: PropTypes.string
};
ReactDOM.render(
<MyTitle title={title} />,
document.getElementById('example')
);
更多验证器说明如下
MyComponent.propTypes = {
// 可以声明 prop 为指定的 JS 基本数据类型,默认情况,这些数据是可选的
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,
// 可以被渲染的对象 numbers, strings, elements 或 array
optionalNode: React.PropTypes.node,
// React 元素
optionalElement: React.PropTypes.element,
// 用 JS 的 instanceof 操作符声明 prop 为类的实例。
optionalMessage: React.PropTypes.instanceOf(Message),
// 用 enum 来限制 prop 只接受指定的值。
optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
// 可以是多个对象类型中的一个
optionalUnion: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.instanceOf(Message)
]),
// 指定类型组成的数组
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
// 指定类型的属性构成的对象
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
// 特定 shape 参数的对象
optionalObjectWithShape: React.PropTypes.shape({
color: React.PropTypes.string,
fontSize: React.PropTypes.number
}),
// 任意类型加上 `isRequired` 来使 prop 不可空。
requiredFunc: React.PropTypes.func.isRequired,
// 不可空的任意类型
requiredAny: React.PropTypes.any.isRequired,
// 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接使用 `console.warn` 或抛异常,因为这样 `oneOfType` 会失效。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error('Validation failed!');
}
}
}
}
React 事件处理
-
React 事件绑定属性的命名采用
驼峰式写法
,而不是小写。<button onClick={activateLasers}>激活按钮</button>
-
在 React 中另一个不同是你不能使用返回 false 的方式阻止默认行为, 你必须明确使用
preventDefault
。function ActionLink() { function handleClick(e) { e.preventDefault(); console.log('链接被点击'); } return ( <a href="#" onClick={handleClick}> 点我 </a> ); }
向事件处理程序传递参数
通常我们会为事件处理程序传递额外的参数。例如,若是 id 是你要删除那一行的 id,以下两种方式都可以向事件处理程序传递参数:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
通过 bind 方式向监听函数传参,在类组件中定义的监听函数,事件对象 e 要排在所传递参数的后面,例如:
class Popper extends React.Component{
constructor(){
super();
this.state = {name:'Hello world!'};
}
preventPop(name, e){ //事件对象e要放在最后
e.preventDefault();
alert(name);
}
render(){
return (
<div>
<p>hello</p>
{/* 通过 bind() 方法传递参数。 */}
<a href="https://reactjs.org" onClick={this.preventPop.bind(this,this.state.name)}>Click</a>
</div>
);
}
}
【未完待续】
参考
标签:入门,render,React,PropTypes,props,组件,ReactDOM 来源: https://blog.csdn.net/qq_37116222/article/details/118083113