React简介
(1)用来构建UI的 JavaScript库
(2)React 不是一个 MVC 框架,仅仅是视图(V)层的库
核心概念:
特点
- 使用 JSX语法 创建组件,实现组件化开发,为函数式的 UI 编程方式打开了大门
- 性能高的让人称赞:通过 diff算法 和 虚拟DOM 实现视图的高效更新
- 使用组件化开发方式,符合现代Web开发的趋势
- 技术成熟,社区完善,配件齐全,适用于大型Web项目(生态系统健全)
- 由Facebook专门的团队维护,技术支持可靠
- ReactNative - Learn once, write anywhere: Build mobile apps with React
- 使用方式简单,性能非常高,支持服务端渲染
- 有利于参与潜力大的项目
key 属性
React提供了一个 key 属性。当子节点带有key属性,React会通过key来匹配原始树和后来的树。
<ul>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
// 新
<ul>
<li key="2017">Connecticut</li>
<li key="2018">Duke</li>
<li key="2019">Villanova</li>
</ul>
执行过程:
现在 React 知道带有key ‘2017’ 的元素是新的,对于 ‘2018’ 和 ‘2019’ 仅仅移动位置即可
说明:key属性在React内部使用,但不会传递给你的组件
推荐:在遍历数据时,推荐在组件中使用 key 属性:
<li key={item.id}>{item.name}</li>
注意:key只需要保持与他的兄弟节点唯一即可,不需要全局唯一
注意:尽可能的减少数组index作为key,数组中插入元素的等操作时,会使得效率底下
React的基本使用
- 安装:npm i -S react react-dom
- react:react 是React库的入口点
- react-dom:提供了针对DOM的方法,比如:把创建的虚拟DOM,渲染到页面上
// 1. 导入 react
import React from 'react'
import ReactDOM from 'react-dom'
// 2. 创建 虚拟DOM
// 参数1:元素名称 参数2:元素属性对象(null表示无) 参数3:当前元素的子元素string||createElement() 的返回值
const divVD = React.createElement('div', {
title: 'hello react'
}, 'Hello React!!!')
// 3. 渲染
// 参数1:虚拟dom对象 参数2:dom对象表示渲染到哪个元素内 参数3:回调函数
ReactDOM.render(divVD, document.getElementById('app'))
createElement()的问题
说明:createElement()方式,代码编写不友好,太复杂
var dv = React.createElement(
"div",
{ className: "shopping-list" },
React.createElement(
"h1",
null,
"Shopping List for "
),
React.createElement(
"ul",
null,
React.createElement(
"li",
null,
"Instagram"
),
React.createElement(
"li",
null,
"WhatsApp"
)
)
)
// 渲染
ReactDOM.render(dv, document.getElementById('app'))
JSX 的基本使用
- 注意:JSX语法,最终会被编译为 createElement() 方法
- 推荐:使用 JSX 的方式创建组件
- JSX - JavaScript XML
- 安装:npm i -D babel-preset-react (依赖与:babel-core/babel-loader)
注意:JSX的语法需要通过 babel-preset-react 编译后,才能被解析执行
/* 1 在 .babelrc 开启babel对 JSX 的转换 */
{
"presets": [
"env", "react"
]
}
/* 2 webpack.config.js */
module: [
rules: [
{ test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ },
]
]
/* 3 在 js 文件中 使用 JSX */
const dv = (
<div title="标题" className="cls container">Hello JSX!</div>
)
/* 4 渲染 JSX 到页面中 */
ReactDOM.render(dv, document.getElementById('app'))
JSX的注意点
- 注意 :
如果在 JSX 中给元素添加类, 需要使用 className 代替 class
类似:label 的 for属性,使用htmlFor代替 - 注意 :在 JSX 中可以直接使用 JS代码,直接在 JSX 中通过 {} 中间写 JS代码即可
- 注意 :在 JSX 中只能使用表达式,但是不能出现 语句!!!
- 注意 :在 JSX 中注释语法:{/* 中间是注释的内容 */}
React组件
组件是由一个个的HTML元素组成的
概念上来讲, 组件就像JS中的函数。它们接受用户输入(props),并且返回一个React对象,用来描述展示在页面中的内容
React创建组件的两种方式
- 通过 JS函数 创建(无状态组件)
- 通过 class 创建(有状态组件)
函数式组件 和 class 组件的使用场景说明:
- 如果一个组件仅仅是为了展示数据,那么此时就可以使用 函数组件
- 如果一个组件中有一定业务逻辑,需要操作数据,那么就需要使用 class 创建组件,因为,此时需要使用 state
JavaScript函数创建
- 函数名称必须为大写字母开头,React通过这个特点来判断是不是一个组件
- 函数必须有返回值,返回值可以是:JSX对象或null
- 返回的JSX,必须有一个根元素
- 组件的返回值使用()包裹,避免换行问题
class创建
在es6中class仅仅是一个语法糖,不是真正的类,本质上还是构造函数+原型 实现继承
给组件传递数据 - 父子组件传递数据
组件中有一个 只读的对象 叫做 props,无法给props添加属性
获取方式:函数参数 props
作用:将传递给组件的属性转化为 props 对象中的属性
function Welcome(props){
// props ---> { username: 'zs', age: 20 }
return (
<div>
<div>Welcome React</div>
<h3>姓名:{props.username}----年龄是:{props.age}</h3>
</div>
)
}
// 给 Hello组件 传递 props:username 和 age(如果你想要传递numb类型是数据 就需要向下面这样)
ReactDOM.reander(<Hello username="zs" age={20}></Hello>, ......)
封装组件到独立的文件中
// 创建Hello2.js组件文件
// 1. 引入React模块
// 由于 JSX 编译后会调用 React.createElement 方法,所以在你的 JSX 代码中必须首先拿到React。
import React from 'react'
// 2. 使用function构造函数创建组件
function Hello2(props){
return (
<div>
<div>这是Hello2组件</div>
<h1>这是大大的H1标签,我大,我骄傲!!!</h1>
<h6>这是小小的h6标签,我小,我傲娇!!!</h6>
</div>
)
}
// 3. 导出组件
export default Hello2
// app.js中 使用组件:
import Hello2 from './components/Hello2'
props和state
JSX语法转化过程
组件的生命周期
简单说:一个组件从开始到最后消亡所经历的各种状态,就是一个组件的生命周期
组件生命周期函数的定义:从组件被创建,到组件挂载到页面上运行,再到页面关闭组件被卸载,这三个阶段总是伴随着组件各种各样的事件,那么这些事件,统称为组件的生命周期函数!
state和setState
组件绑定事件
1 通过React事件机制 onClick 绑定
2 JS原生方式绑定(通过 ref 获取元素)
事件绑定中的this
- 通过 bind 绑定
- 通过 箭头函数 绑定
通过bind绑定
原理:bind能够调用函数,改变函数内部this的指向,并返回一个新函数
说明:bind第一个参数为返回函数中this的指向,后面的参数为传给返回函数的参数
// 自定义方法:
handleBtnClick(arg1, arg2) {
this.setState({
msg: '点击事件修改state的值' + arg1 + arg2
})
}
render() {
return (
<div>
<button onClick={
// 无参数
// this.handleBtnClick.bind(this)
// 有参数
this.handleBtnClick.bind(this, 'abc', [1, 2])
}>事件中this的处理</button>
<h1>{this.state.msg}</h1>
</div>
)
}
在构造函数中使用bind
constructor() {
super()
this.handleBtnClick = this.handleBtnClick.bind(this)
}
// render() 方法中:
<button onClick={ this.handleBtnClick }>事件中this的处理</button>
通过箭头函数绑定
原理:箭头函数中的this由所处的环境决定,自身不绑定this
<input type="button" value="在构造函数中绑定this并传参" onClick={
() => { this.handleBtnClick('参数1', '参数2') }
} />
handleBtnClick(arg1, arg2) {
this.setState({
msg: '在构造函数中绑定this并传参' + arg1 + arg2
});
}
受控组件
props校验
React 单向数据流
组件通讯
- 父 -> 子:props
- 子 -> 父:父组件通过props传递回调函数给子组件,子组件调用函数将数据作为参数传递给父组件
- 兄弟组件:因为React是单向数据流,因此需要借助父组件进行传递,通过父组件回调函数改变兄弟组件的props
React中的状态管理: flux(提出状态管理的思想) -> Redux -> mobx
Vue中的状态管理: Vuex
简单来说,就是统一管理了项目中所有的数据,让数据变的可控
组件通讯
Context特性
- 注意:如果不熟悉React中的数据流,不推荐使用这个属性
这是一个实验性的API,在未来的React版本中可能会被更改 - 作用:跨级传递数据(爷爷给孙子传递数据),避免向下每层手动地传递props
- 说明:需要配合PropTypes类型限制来使用
class Grandfather extends React.Component {
// 类型限制(必须),静态属性名称固定
static childContextTypes = {
color: PropTypes.string.isRequired
}
// 传递给孙子组件的数据
getChildContext() {
return {
color: 'red'
}
}
render() {
return (
<Father></Father>
)
}
}
class Child extends React.Component {
// 类型限制,静态属性名字固定
static contextTypes = {
color: PropTypes.string
}
render() {
return (
// 从上下文对象中获取爷爷组件传递过来的数据
<h1 style={{ color: this.context.color }}>爷爷告诉文字是红色的</h1>
)
}
}
class Father extends React.Component {
render() {
return (
<Child></Child>
)
}
}
react-router
react router 官网
react router github
安装:npm i -S react-router-dom
Router组件本身只是一个容器,真正的路由要通过Route组件定义
使用步骤
- 导入路由组件
- 使用 作为根容器,包裹整个应用(JSX)
在整个应用程序中,只需要使用一次 - 使用 作为链接地址,并指定to属性
- 使用 展示路由内容
// 1 导入组件
import {
HashRouter as Router,
Link, Route
} from 'react-router-dom'
// 2 使用 <Router>
<Router>
// 3 设置 Link
<Menu.Item key="1"><Link to="/">首页</Link></Menu.Item>
<Menu.Item key="2"><Link to="/movie">电影</Link></Menu.Item>
<Menu.Item key="3"><Link to="/about">关于</Link></Menu.Item>
// 4 设置 Route
// exact 表示:绝对匹配(完全匹配,只匹配:/)
<Route exact path="/" component={HomeContainer}></Route>
<Route path="/movie" component={MovieContainer}></Route>
<Route path="/about" component={AboutContainer}></Route>
</Router>
注意
- :作为整个组件的根元素,是路由容器,只能有一个唯一的子元素
- :类似于vue中的标签,to 属性指定路由地址
- :类似于vue中的,指定路由内容(组件)展示位置
路由参数
配置:通过Route中的path属性来配置路由参数
获取:this.props.match.params 获取
// 配置路由参数
<Route path="/movie/:movieType"></Route>
// 获取路由参数
const type = this.props.match.params.movieType
路由跳转
-
react router - history
-
history.push() 方法用于在JS中实现页面跳转
-
history.go(-1) 用来实现页面的前进(1)和后退(-1)
this.props.history.push('/movie/movieDetail/' + movieId)