1、React简介
1.1、React概述
React
是用于构建用户界面的 javascript
库,具有声明式、组件化等特点。
1.2、MVC和MVVM模式
MVC(Model-View-Controller,模型-视图-控制器),Model指模型数据,View是显示的界面,Controller是控制层,控制层用于接收到用户的操作,然后进行一系列的处理后,发送给Model,接收到Model的响应后再交给View视图层。
MVVM(Model-View-ViewModel,模型-视图-视图模型),Model指模型数据,View是指浏览器渲染的网页,ViewMode是Model和View的桥梁,称为视图模型,由ViewModel完成数据的绑定。
在Vue中,JS对象就是Model,HTML标签就是View,Vue实例就是ViewModel。
2、React环境搭建
2.1、使用webpack搭建React开发环境
参考博客:https://blog.youkuaiyun.com/p445098355/article/details/104517094
2.2、使用create-react-app脚手架
安装脚手架
cnpm i -g create-react-app
创建项目
create-react-app 项目名称
3、JSX语法
jsx
全程是 javascript XML
,是一个 JavaScript 的语法扩展。jsx
要按照 xml
的编写规范,即:
- 最外层只能有一个根标记;
- 每个标记都必须要有闭合标签;
在 jsx
中可以使用 {...}
来编写 javascript
表达式。
4、React组件
4.1、函数组件
使用构造函数声明的组件被称为函数组件,因其内部没有 state
属性,所以又被称为无状态组件,代码如下:
import React from 'react';
import ReactDOM from 'react-dom';
const App = () => {
return (
<div>
函数组件
</div>
)
}
ReactDOM.render(<App />,document.getElementById('root'));
可以通过 props
属性获取到组件标签上定义的属性值,例如:
import React from 'react';
import ReactDOM from 'react-dom';
const App = (props) => {
return (
<div>
函数组件,props值: {props.name}
</div>
)
}
ReactDOM.render(<App name="Tom" />,document.getElementById('root'));
4.2、类组件
使用 class
关键字创建的组件,称为类组件,因其内部可以有 state
属性,又被称为有状态组件,代码如下:
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component {
render() {
return (
<div>
类组件
</div>
)
}
}
ReactDOM.render(<App name="Tom" />,document.getElementById('root'));
在使用类组件的标签时,标签上定义的属性都会通过类组件的构造函数,传递到组件内部,然后在组件内容使用 this.props
获取到外界的传值,代码如下:
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component {
//构造函数
constructor(props){
super(props)
console.log(props)
}
render() {
return (
<div>
类组件,props值: {this.props.name}
</div>
)
}
}
ReactDOM.render(<App name="Tom" />,document.getElementById('root'));
每个类组件都有自己独享的内部状态,即 state
属性。如果要操作 state
必须要使用 setState()
函数,该函数是一个异步函数,对 state
修改后,会再次调用 render()
函数重新渲染页面。
class App extends React.Component {
//构造函数
constructor(props){
super(props)
this.state = {
value: 'hello'
}
}
//按钮点击事件,接收到视图层的指令,操作数据模型,最后在把操作结果返回给视图
handleClick(str){
this.setState({
value: str
})
}
render() {
return (
<div>
{this.state.value}
<button onClick={this.handleClick.bind(this,'world')}>修改state</button>
</div>
)
}
}
ReactDOM.render(<App name="Tom" />,document.getElementById('root'));
4.3、函数组件和类组件的区别
在说明函数组件和类组件的区别时,要看3个方面:
- 组件内是否有
this
; - 组件内是否有
state
; - 组件内是否有生命周期钩子;
只要符合上面的3点,就是一个有状态组件,即类组件。
4.4、组件通信
父组件向子组件传值
import React from 'react';
import ReactDOM from 'react-dom';
// import App from './App';
class App extends React.Component {
render(){
return (
<div>
{/* 自定义组件,可以在组件上自定义属性 */}
<Button text="百度一下" subText="点击提交数据" textColor="red"/>
</div>
)
}
}
//无状态组件,只显示UI效果,没有太多的业务逻辑
const Button = (props) => {
return (
<button title={props.subText} style={{color: props.textColor}}>{props.text}</button>
)
}
ReactDOM.render(<App name="Tom" />,document.getElementById('root'));
子组件向父组件传值
import React from 'react';
import ReactDOM from 'react-dom';
// import App from './App';
class App extends React.Component {
//自定义组件的点击事件,text为默认参数,即封装Button组件时传入的一个参数
handleClick(text){
console.log('自定义组件被点击了。。。。',text)
}
render(){
return (
<div>
{/* 自定义组件,可以在组件上自定义属性,也可以自定义事件 */}
<Button text="百度一下" subText="点击提交数据" textColor="red" onClick={this.handleClick.bind(this)}/>
</div>
)
}
}
//无状态组件,只显示UI效果,没有太多的业务逻辑
const Button = (props) => {
return (
<button title={props.subText} style={{color: props.textColor}} onClick={()=>{
props.onClick(props.text)
}}>{props.text}</button>
)
}
ReactDOM.render(<App name="Tom" />,document.getElementById('root'));
4.5、封装自定义组件
自定义按钮组件
import React, { Component } from 'react'
export default class Button extends Component {
//HTML的button标签原生点击事件函数
handleClick(){
this.props.onClick()
}
render() {
return (
<div>
<button style={{color: this.props.fontColor}} onClick={this.handleClick.bind(this)}>{this.props.text}</button>
</div>
)
}
}
自定义输入框组件
import React, { Component } from 'react'
export default class Input extends Component {
//input标签原生键盘事件的函数
handlePress(e){
if(e.charCode === 13){
this.props.onEnter(e.target.value)
}
}
render() {
return (
<div>
<input onKeyPress={this.handlePress.bind(this)}></input>
</div>
)
}
}
在父组件中使用自定义组件
import React, { Component } from 'react'
import Button from './Button'
import Input from './Input'
export default class App extends Component {
handleClick(){
console.log('click....')
}
//Input组件上的回车事件
handleEnter(val){
console.log('enter...',val)
}
render() {
return (
<div>
<Input onEnter={this.handleEnter.bind(this)}></Input>
<Button text="提交" fontColor="red" onClick={this.handleClick.bind(this)}></Button>
</div>
)
}
}
5、UI组件库
5.1、使用Element-React组件库
需要安装:
# 安装element-react
cnpm i element-react --save
# 安装elementui的主题
cnpm install element-theme-default --save
# 按钮react-hot-loader
cnpm install react-hot-loader@next -D
Button组件使用案例:
import React, { Component } from 'react'
import {
Button
} from 'element-react'
import 'element-theme-default'
export default class App extends Component {
constructor(){
super()
this.state = {
isLoading: false,
btnText: '点击下载'
}
}
handleLoading = ()=>{
this.setState({
btnText: '下载中',
isLoading: true
},()=>{
//模拟下载过程
setTimeout(()=>{
this.setState({
btnText: '下载完成',
isLoading: false
})
},2000)
})
}
render() {
return (
<div>
<Button type="info" loading={this.state.isLoading} onClick={this.handleLoading}>
{this.state.btnText}
</Button>
<Button>
上传
<i className="el-icon-upload2"></i>
</Button>
</div>
)
}
}
Menu和Table组件的使用案例:
import React, { Component } from 'react'
import {
Button,
Menu,
Table
} from 'element-react'
import 'element-theme-default'
export default class App extends Component {
constructor(){
super()
this.state = {
column: [
{
label: '姓名',
prop: 'name'
},
{
label: '年龄',
prop: 'age'
},
{
label: '电话',
prop: 'phone'
},
{
label: '操作',
render: (obj,e,index)=>{ //渲染函数的默认参数为当前点击的数据对象
return (
<React.Fragment>
<Button type="info" size="small">修改</Button>
<Button type="danger" size="small">删除</Button>
</React.Fragment>
)
}
}
],
data: [
{
name: '张三',
age: 20,
phone: '13099998888'
},
{
name: '李四',
age: 21,
phone: '13099998888'
},
{
name: '王五',
age: 22,
phone: '13099998888'
}
]
}
}
render() {
return (
<div>
<Menu mode="horizontal" theme="dark" defaultActive="1" style={{marginBottom: '20px'}}>
<Menu.Item index="1">首页</Menu.Item>
<Menu.SubMenu index="2" title="新闻">
<Menu.Item index="2-1">国内新闻</Menu.Item>
<Menu.Item index="2-2">国际新闻</Menu.Item>
<Menu.Item index="2-3">社会新闻</Menu.Item>
</Menu.SubMenu>
</Menu>
<Table style={{width: '100%'}} columns={this.state.column} data={this.state.data}></Table>
</div>
)
}
}
5.2、Ant Design UI库
安装
cnpm i antd --save
引入组件
# 按需引入
import { DatePicker } from 'antd';
# 引入样式
import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
6、路由
BrowserRouter
<BrowserRouter>
使用 HTML5 提供的 history API (pushState
, replaceState
和 popstate
事件) 来保持 UI 和 URL 的同步。一个应用程序中只需要有一个 <BrowserRouter>
即可。
在 index.js
中使用:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {BrowserRouter} from 'react-router-dom'
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
,document.getElementById('root'));
HashRouter
<HashRouter>
使用 URL 的 hash
部分(即 window.location.hash
)来保持 UI 和 URL 的同步。与 <BrowserRouter>
用法类似,但是 <HashRouter>
在页面中显示的路由地址里有 #
符号。
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {HashRouter} from 'react-router-dom'
ReactDOM.render(
<HashRouter>
<App />
</HashRouter>
,document.getElementById('root'));
Link
为你的应用提供声明式的、可访问的导航链接。
import { Link } from 'react-router-dom';
<Link to="/about">About</Link>
配合 Route
使用。
Route
<Route>
可能是 React Router 中最重要的组件,它可以帮助你理解和学习如何更好的使用 React Router。它最基本的职责是在其 path
属性与某个 location 匹配时呈现一些 UI。
import { BrowserRouter as Router, Route } from 'react-router-dom';
<Router>
<div>
<Route exact path="/" component={Home} />
<Route path="/news" component={News} />
</div>
</Router>
Link、Route配合使用案例:
import React, { Component } from 'react'
import {Menu} from 'element-react'
import 'element-theme-default'
import {Link,Route,Switch} from 'react-router-dom'
export default class App extends Component {
render() {
return (
<div>
<Menu mode="horizontal" theme="dark" defaultActive="1" style={{marginBottom: '20px'}}>
<Menu.Item index="1">首页</Menu.Item>
<Menu.SubMenu index="2" title="新闻">
<Menu.Item index="2-1">
<Link to="/guonei">国内新闻</Link>
</Menu.Item>
<Menu.Item index="2-2">
<Link to="/guoji">国际新闻</Link>
</Menu.Item>
<Menu.Item index="2-3">
<Link to="/shehui">社会新闻</Link>
</Menu.Item>
</Menu.SubMenu>
</Menu>
<Switch>
<Route path="/guonei" component={GuoneiNews}></Route>
<Route path="/guoji" component={GuojiNews}></Route>
<Route path="/shehui" component={ShehuiNews}></Route>
</Switch>
</div>
)
}
}
参考博客:https://www.jianshu.com/p/97e4af32811a
7、Redux状态管理
Store
用于连接 action
和 reducer
重要对象,一个redux应用程序中只能有一个 store
对象。
import { createStore } from 'redux'
import todoApp from './reducers'
let store = createStore(todoApp)
Reducer
Reducers 指定了应用状态的变化如何响应 actions 并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。
Action
Action 是把数据从应用(译者注:这里之所以不叫 view 是因为这些数据有可能是服务器响应,用户输入或其它非 view 的数据 )传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过 store.dispatch()
将 action 传到 store。
const action = {
type: "ADD_TODO",
text: 'Build my first Redux app'
}
核心API
在使用redux时,需要掌握的核心API:
- store.getState() :用于获取最新的store对象
- store.subscrbe() :用于监听store中的数据变化
- store.dispatch() :用于向reducer派发action对象