1) 英文官网: https://reactjs.org/
2) 中文官网: https://doc.react-china.org/
1) 用于构建用户界面的 JavaScript 库(只关注于View)
2) 由Facebook开源
1) Declarative(声明式编码)
2) Component-Based(组件化编码)
3) Learn Once, Write Anywhere(支持客户端与服务器渲染)
4) 高效
5) 单向数据流
1) 虚拟(virtual)DOM, 不总是直接操作DOM
2) DOM Diff算法, 最小化页面重绘
注意: 此时只是测试语法使用, 并不是真实项目开发使用
1) react.js: React的核心库
2) react-dom.js: 提供操作DOM的react扩展库
3) babel.min.js: 解析JSX语法代码转为纯JS语法代码的库
<script type="text/javascript" src="../js/react.development.js">script> |
<script type="text/babel"> //必须声明babel |
React Developer Tools.crx
1) React提供了一些API来创建一种 `特别` 的一般js对象
a. var element = React.createElement('h1', {id:'myTitle'},'hello')
b. 上面创建的就是一个简单的虚拟DOM对象
2) 虚拟DOM对象最终都会被React转换为真实的DOM
3) 我们编码时基本只需要操作react的虚拟DOM相关数据, react会转换为真实DOM变化而更新界面
1) 全称: JavaScript XML
2) react定义的一种类似于XML的JS扩展语法: XML+JS
3) 作用: 用来创建react虚拟DOM(元素)对象
a. var ele = Hello JSX!
b. 注意1: 它不是字符串, 也不是HTML/XML标签
c. 注意2: 它最终产生的就是一个JS对象
4) 标签名任意: HTML标签或其它标签
5) 标签属性任意: HTML标签属性或其它
6) 基本语法规则
a. 遇到 <开头的代码, 以标签的语法解析: html同名标签转换为html同名元素, 其它标签需要特别解析
b. 遇到以 { 开头的代码,以JS语法解析: 标签中的js代码必须用{ }包含
7) babel.js的作用
a. 浏览器不能直接解析JSX代码, 需要babel转译为纯JS的代码才能运行
b. 只要用了JSX,都要加上type="text/babel", 声明需要babel来处理
1) 语法: ReactDOM.render(virtualDOM, containerDOM)
2) 作用: 将虚拟DOM元素渲染到页面中的真实容器DOM中显示
3) 参数说明
a. 参数一: 纯js或jsx创建的虚拟dom对象
b. 参数二: 用来包含虚拟DOM元素的真实dom元素对象(一般是一个div)
1) 纯JS(一般不用)
React.createElement('h1', {id:'myTitle'}, title)
2) JSX:
{title}
需求: 动态展示列表数据
1) 理解: 向外提供特定功能的js程序, 一般就是一个js文件
2) 为什么: js代码更多更复杂
3) 作用: 复用js, 简化js的编写, 提高js运行效率
1) 理解: 用来实现特定(局部)功能效果的代码集合(html/css/js)
2) 为什么: 一个界面的功能更复杂
3) 作用: 复用编码, 简化项目编码, 提高运行效率
当应用的js都以模块来编写的, 这个应用就是一个模块化的应用
当应用是以多组件的方式实现, 这个应用就是一个组件化的应用
1) 定义组件(2种方式)
/*方式1: 工厂函数组件(简单组件)*/ function MyComponent () { /*方式2: ES6类组件(复杂组件)*/ class MyComponent2 extends React.Component { |
2) 渲染组件标签
ReactDOM.render(<MyComponent />, document.getElementById('example1')) |
1) 组件名必须首字母大写
2) 虚拟DOM元素只能有一个根元素
3) 虚拟DOM元素必须有结束标签
1) React内部会创建组件实例对象
2) 得到包含的虚拟DOM并解析为真实DOM
3) 插入到指定的页面元素内部
1) state是组件对象最重要的属性, 值是对象(可以包含多个数据)
2) 组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)
1) 初始化状态:
constructor (props) {
super(props)
this.state = {
stateProp1 : value1,
stateProp2 : value2
}
}
2) 读取某个状态值
this.state.statePropertyName
3) 更新状态---->组件界面更新
this.setState({
stateProp1 : value1,
stateProp2 : value2
})
需求: 自定义用来显示一个人员信息的组件
1). 姓名必须指定
2). 如果性别没有指定, 默认为男
3). 如果年龄没有指定, 默认为18
1) 每个组件对象都会有props(properties的简写)属性
2) 组件标签的所有属性都保存在props中
1) 通过标签属性从组件外向组件内传递变化的数据
2) 注意: 组件内部不要修改props数据
1) 内部读取某个属性值
this.props.propertyName
2) 对props中的属性值进行类型限制和必要性限制
Person.propTypes = {
name: React.PropTypes.string.isRequired,
age: React.PropTypes.number.isRequired
}
3) 扩展属性: 将对象的所有属性通过props传递
4) 默认属性值
Person.defaultProps = {
name: 'Mary'
}
5) 组件类的构造函数
constructor (props) {
super(props)
console.log(props) // 查看所有属性
}
问题: 请区别一下组件的props和state属性
1) state: 组件自身内部可变化的数据
2) props: 从组件外部向组件内部传递数据, 组件内部只读不修改
需求: 自定义组件, 功能说明如下:
2. 点击按钮, 提示第一个输入框中的值
3. 当第2个输入框失去焦点时, 提示这个输入框中的值
1) 组件内的标签都可以定义ref属性来标识自己
a. ref={input => this.msgInput = input}/>
b. 回调函数在组件初始化渲染完或卸载时自动调用
2) 在组件中可以通过this.msgInput来得到对应的真实DOM元素
3) 作用: 通过ref获取组件内容特定标签对象, 进行读取其相关数据
1) 通过onXxx属性指定组件的事件处理函数(注意大小写)
a. React使用的是自定义(合成)事件, 而不是使用的原生DOM事件
b. React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)
2) 通过event.target得到发生事件的DOM元素对象
handleFocus(event) {
event.target //返回input对象
}
1) 组件内置的方法中的this为组件对象
2) 在组件类中自定义的方法中this为null
a. 强制绑定this: 通过函数对象的bind()
b. 箭头函数(ES6模块化编码时才能使用)
功能: 组件化实现此功能
1. 显示所有todo列表
2. 输入文本, 点击按钮显示到列表的首位, 并清除输入的文本
1) 拆分组件: 拆分界面,抽取组件
2) 实现静态组件: 使用组件实现静态页面效果
3) 实现动态组件
a. 动态显示初始化数据
b. 交互功能(从绑定事件监听开始)
需求: 自定义包含表单的组件
1. 输入用户名密码后, 点击登陆提示输入信息
2. 不提交表单
1) 问题: 在react应用中, 如何收集表单输入数据
2) 包含表单的组件分类
a. 受控组件: 表单项输入数据能自动收集成状态
b. 非受控组件: 需要时才手动读取表单输入框中的数据
需求: 自定义组件
1. 让指定的文本做显示/隐藏的渐变动画
2. 切换持续时间为2S
3. 点击按钮从界面中移除组件界面
1) 组件对象从创建到死亡它会经历特定的生命周期阶段
2) React组件对象包含一系列的勾子函数(生命周期回调函数), 在生命周期特定时刻回调
3) 我们在定义组件时, 可以重写特定的生命周期回调函数, 做特定的工作
1) 组件的三个生命周期状态:
* Mount:插入真实 DOM
* Update:被重新渲染
* Unmount:被移出真实 DOM
2) React 为每个状态都提供了勾子(hook)函数
* componentWillMount()
* componentDidMount()
* componentWillUpdate()
* componentDidUpdate()
* componentWillUnmount()
3) 生命周期流程:
a. 第一次初始化渲染显示: ReactDOM.render()
* constructor(): 创建对象初始化state
* componentWillMount() : 将要插入回调
* render() : 用于插入虚拟DOM回调
* componentDidMount() : 已经插入回调
b. 每次更新state: this.setSate()
* componentWillUpdate() : 将要更新回调
* render() : 更新(重新渲染)
* componentDidUpdate() : 已经更新回调
c. 移除组件: ReactDOM.unmountComponentAtNode(containerDom)
* componentWillUnmount() : 组件将要被移除回调
1) render(): 初始化渲染或更新渲染调用
2) componentDidMount(): 开启监听, 发送ajax请求
3) componentWillUnmount(): 做一些收尾工作, 如: 清理定时器
componentWillReceiveProps(): 后面需要时讲
class HelloWorld extends React.Component { |
1) xxx脚手架: 用来帮助程序员快速创建一个基于xxx库的模板项目
a. 包含了所有需要的配置
b. 指定好了所有的依赖
c. 可以直接安装/编译/运行一个简单效果
2) react提供了一个用于创建react项目的脚手架库: create-react-app
3) 项目的整体技术架构为: react + webpack + es6 + eslint
4) 使用脚手架开发的项目的特点: 模块化, 组件化, 工程化
npm install -g create-react-app
create-react-app hello-react
cd hello-react
npm start
ReactNews
|--node_modules---第三方依赖模块文件夹
|--public
|-- index.html-----------------主页面
|--scripts
|-- build.js-------------------build打包引用配置
|-- start.js-------------------start运行引用配置
|--src------------源码文件夹
|--components-----------------react组件
|--index.js-------------------应用入口js
|--.gitignore------git版本管制忽略的配置
|--package.json----应用包配置文件
|--README.md-------应用描述说明的readme文件
应用组件: App
* state: comments/array
添加评论组件: CommentAdd
* state: username/string, content/string
* props: add/func
评论列表组件: CommentList
* props: comment/object, delete/func, index/number
评论项组件: CommentItem
* props: comments/array, delete/func
动态展示初始化数据
* 初始化状态数据
* 传递属性数据
响应用户操作, 更新组件界面
* 绑定事件监听, 并处理
* 更新state
1) React本身只关注于界面, 并不包含发送ajax请求的代码
2) 前端应用需要通过ajax请求与后台进行交互(json数据)
3) react应用中需要集成第三方ajax库(或自己封装)
1) jQuery: 比较重, 如果需要另外引入不建议使用
2) axios: 轻量级, 建议使用
a. 封装XmlHttpRequest对象的ajax
b. promise风格
c. 可以用在浏览器端和node服务器端
3) fetch: 原生函数, 但老版本浏览器不支持
a. 不再使用XmlHttpRequest对象提交ajax请求
b. 为了兼容低版本的浏览器, 可以引入兼容库fetch.js
需求:
1. 界面效果如下
2. 根据指定的关键字在github上搜索匹配的最受关注的库
3. 显示库名, 点击链接查看库
4. 测试接口: https://api.github.com/search/repositories?q=r&sort=stars
https://github.com/axios/axios
1) GET请求
axios.get('/user?ID=12345') .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }); axios.get('/user', { params: { ID: 12345 } }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
|
2) POST请求
axios.post('/user', { firstName: 'Fred', lastName: 'Flintstone' }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }); |
1) https://github.github.io/fetch/
2) https://segmentfault.com/a/1190000003810652
1) GET请求
fetch(url).then(function(response) { return response.json() }).then(function(data) { console.log(data) }).catch(function(e) { console.log(e) }); |
2) POST请求
fetch(url, { method: "POST", body: JSON.stringify(data), }).then(function(data) { console.log(data) }).catch(function(e) { console.log(e) }) |
App
* state: searchName/string
Search
* props: setSearchName/func
List
* props: searchName/string
* state: firstView/bool, loading/bool, users/array, errMsg/string
componentWillReceiveProps(nextProps): 监视接收到新的props, 发送ajax
使用axios库发送ajax请求
1) 共同的数据放在父组件上, 特有的数据放在自己组件内部(state)
2) 通过props可以传递一般数据和函数数据, 只能一层一层传递
3) 一般数据-->父组件传递数据给子组件-->子组件读取数据
4) 函数数据-->子组件传递数据给父组件-->子组件调用函数
1) 工具库: PubSubJS
2) 下载: npm install pubsub-js --save
3) 使用:
import PubSub from 'pubsub-js' //引入
PubSub.subscribe('delete', function(data){ }); //订阅
PubSub.publish('delete', data) //发布消息
后面专门讲解
1) 绑定事件监听
a. 事件名(类型): 只有有限的几个, 不能随便写
b. 回调函数
2) 触发事件
a. 用户操作界面
b. 事件名(类型)
c. 数据()
1) 绑定事件监听
a. 事件名(类型): 任意
b. 回调函数: 通过形参接收数据, 在函数体处理事件
2) 触发事件(编码)
a. 事件名(类型): 与绑定的事件监听的事件名一致
b. 数据: 会自动传递给回调函数
1) 定义常量/变量: const/let
2) 解构赋值: let {a, b} = this.props import {aa} from 'xxx'
3) 对象的简洁表达: {a, b}
4) 箭头函数:
a. 常用场景
* 组件的自定义方法: xxx = () => {}
* 参数匿名函数
b. 优点:
* 简洁
* 没有自己的this,使用引用this查找的是外部this
5) 扩展(三点)运算符: 拆解对象(const MyProps = {},
6) 类: class/extends/constructor/super
ES6模块化: export default | import
1) react的一个插件库
2) 专门用来实现一个SPA应用
3) 基于react的项目基本都会用到此库
1) 单页Web应用(single page web application,SPA)
2) 整个应用只有一个完整的页面
3) 点击页面中的链接不会刷新页面, 本身也不会向服务器发请求
4) 当点击路由链接时, 只会做页面的局部更新
5) 数据都需要通过ajax请求获取, 并在前端异步展现
1) 什么是路由?
a. 一个路由就是一个映射关系(key:value)
b. key为路由路径, value可能是function/component
2) 路由分类
a. 后台路由: node服务器端路由, value是function, 用来处理客户端提交的请求并返回一个响应数据
b. 前台路由: 浏览器端路由, value是component, 当请求的是路由path时, 浏览器端前没有发送http请求, 但界面会更新显示对应的组件
3) 后台路由
a. 注册路由: router.get(path, function(req, res))
b. 当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据
4) 前端路由
a. 注册路由:
b. 当浏览器的hash变为#about时, 当前路由组件就会变为About组件
1) history库
a. 网址: https://github.com/ReactTraining/history
b. 管理浏览器会话历史(history)的工具库
c. 包装的是原生BOM中window.history和window.location.hash
2) history API
a. History.createBrowserHistory(): 得到封装window.history的管理对象
b. History.createHashHistory(): 得到封装window.location.hash的管理对象
c. history.push(): 添加一个新的历史记录
d. history.replace(): 用一个新的历史记录替换当前的记录
e. history.goBack(): 回退到上一个历史记录
f. history.goForword(): 前进到下一个历史记录
g. history.listen(function(location){}): 监视历史记录的变化
3) 测试
html> |
1)
2)
3)
4)
5)
6)
7)
1) history对象
2) match对象
3) withRouter函数
1) 下载react-router: npm install --save react-router@4
2) 引入bootstrap.css:
import React from 'react' |
import React from 'react' |
import React from 'react' |
import React from 'react' |
.activeClass { |
6.3.8. 入口JS: index.js
import React from 'react' |
import React from 'react' |
import React from 'react' |
import React from 'react' |
import React from 'react' |
import React from 'react' |
import React from 'react' |
1) 官网: http://www.material-ui.com/#/
2) github: https://github.com/callemall/material-ui
1) PC官网: https://ant.design/index-cn
2) 移动官网: https://mobile.ant.design/index-cn
3) Github: https://github.com/ant-design/ant-design/
4) Github: https://github.com/ant-design/ant-design-mobile/
npm install create-react-app -g
create-react-app antm-demo
cd antm-demo
npm start
1) 下载
npm install antd-mobile --save
2) src/App.jsx
import React, {Component} from 'react' |
3) src/index.js
import React from 'react'; |
4) index.html
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" /> <script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js">script>
|
1) 下载依赖包
yarn add react-app-rewired --dev
yarn add babel-plugin-import --dev
2) 修改默认配置:
l package.json
"scripts": { |
l config-overrides.js
const {injectBabelPlugin} = require('react-app-rewired'); |
3) 编码
// import 'antd-mobile/dist/antd-mobile.css' // import Button from 'antd-mobile/lib/button' |
1) 英文文档: https://redux.js.org/
2) 中文文档: http://www.redux.org.cn/
3) Github: https://github.com/reactjs/redux
1) redux是一个独立专门用于做状态管理的JS库(不是react插件库)
2) 它可以用在react, angular, vue等项目中, 但基本与react配合使用
3) 作用: 集中式管理react应用中多个组件共享的状态
1) 总体原则: 能不用就不用, 如果不用比较吃力才考虑使用
2) 某个组件的状态,需要共享
3) 某个状态需要在任何地方都可以拿到
4) 一个组件需要改变全局状态
5) 一个组件需要改变另一个组件的状态
1) 作用:
创建包含指定reducer的store对象
2) 编码:
import {createStore} from 'redux'
import counter from './reducers/counter'
const store = createStore(counter)
1) 作用:
redux库最核心的管理对象
2) 它内部维护着:
state
reducer
3) 核心方法:
getState()
dispatch(action)
subscribe(listener)
4) 编码:
store.getState()
store.dispatch({type:'INCREMENT', number})
store.subscribe(render)
1) 作用:
应用上基于redux的中间件(插件库)
2) 编码:
import {createStore, applyMiddleware} from 'redux'
import thunk from 'redux-thunk' // redux异步中间件
const store = createStore(
counter,
applyMiddleware(thunk) // 应用上异步中间件
)
1) 作用:
合并多个reducer函数
2) 编码:
export default combineReducers({
user,
chatUser,
chat
})
1) 标识要执行行为的对象
2) 包含2个方面的属性
a. type: 标识属性, 值为字符串, 唯一, 必要属性
b. xxx: 数据属性, 值类型任意, 可选属性
3) 例子:
const action = {
type: 'INCREMENT',
data: 2
}
4) Action Creator(创建Action的工厂函数)
const increment = (number) => ({type: 'INCREMENT', data: number})
1) 根据老的state和action, 产生新的state的纯函数
2) 样例
export default function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + action.data
case 'DECREMENT':
return state - action.data
default:
return state
}
}
3) 注意
a. 返回一个新的状态
b. 不要修改原来的状态
1) 将state,action与reducer联系在一起的对象
2) 如何得到此对象?
import {createStore} from 'redux'
import reducer from './reducers'
const store = createStore(reducer)
3) 此对象的功能?
getState(): 得到state
dispatch(action): 分发action, 触发reducer调用, 产生新的state
subscribe(listener): 注册监听, 当产生了新的state时, 自动调用
npm install --save redux
/* |
/* |
/* |
/*
|
import React from 'react' |
1) redux与react组件的代码耦合度太高
2) 编码不够简洁
1) 一个react插件库
2) 专门用来简化react应用中使用redux
1) UI组件
a. 只负责 UI 的呈现,不带有任何业务逻辑
b. 通过props接收数据(一般数据和函数)
c. 不使用任何 Redux 的 API
d. 一般保存在components文件夹下
2) 容器组件
a. 负责管理数据和业务逻辑,不负责UI的呈现
b. 使用 Redux 的 API
c. 一般保存在containers文件夹下
1) Provider
让所有组件都可以得到state数据
2) connect()
用于包装 UI 组件生成容器组件
import { connect } from 'react-redux'
connect(
mapStateToprops,
mapDispatchToProps
)(Counter)
3) mapStateToprops()
将外部的数据(即state对象)转换为UI组件的标签属性
const mapStateToprops = function (state) {
return {
value: state
}
}
4) mapDispatchToProps()
将分发action的函数转换为UI组件的标签属性
简洁语法可以直接指定为actions对象或包含多个action方法的对象
1) 下载依赖包
npm install --save react-redux
2) redux/action-types.js
不变
3) redux/actions.js
不变
4) redux/reducers.js
不变
5) components/counter.jsx
/* |
6) containters/app.jsx
/* |
7) index.js
import React from 'react'
|
1) redux默认是不能进行异步处理的,
2) 应用中又需要在redux中执行异步任务(ajax, 定时器)
npm install --save redux-thunk
import {createStore, applyMiddleware} from 'redux' |
// 异步action creator(返回一个函数) |
incrementAsync = () => { |
import {increment, decrement, incrementAsync} from '../redux/actions' // 向外暴露连接App组件的包装组件 |
redux-devtools.crx
npm install --save-dev redux-devtools-extension
import { composeWithDevTools } from 'redux-devtools-extension'
|
1) 一类特别的函数: 只要是同样的输入,必定得到同样的输出
2) 必须遵守以下一些约束
a. 不得改写参数
b. 不能调用系统 I/O 的API
c. 能调用Date.now()或者Math.random()等不纯的方法
3) reducer函数必须是一个纯函数
4) 理解: 一类特别的函数
a. 情况1: 参数是函数
b. 情况2: 返回是函数
5) 常见的高阶函数:
a. 定时器设置函数
b. 数组的map()/filter()/reduce()/find()/bind()
c. react-redux中的connect函数
6) 作用:
能实现更加动态, 更加可扩展的功能