react – JSX
React 背景引见
React 起源于 Facebook 的内部项目,因为该公司对市场上一切 JavaScript MVC 框架,都不惬意,就决议自身写一套,用来架设 Instagram 的网站。做出来今后,发明这套东西很好用,就在2013年5月开源了。
什么是React
A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES
- 用来构建UI的 JavaScript库
- React 不是一个 MVC 框架,仅仅是视图(V)层的库
- React 官网
- React 中文文档
特征
- 1 运用 JSX语法 建立组件,完成组件化开辟,为函数式的 UI 编程体式格局打开了大门
- 2 机能高的让人赞美:经由历程
diff算法
和假造DOM
完成视图的高效更新 - 3 HTML仅仅是个最先
> JSX --TO--> EveryThing
- JSX --> HTML
- JSX --> native ios或android中的组件(XML)
- JSX --> VR
- JSX --> 物联网
为何要用React
- 1 运用
组件化
开辟体式格局,相符当代Web开辟的趋向 - 2 手艺成熟,社区完美,配件完整,实用于大型Web项目(生态系统健全)
- 3 由Facebook特地的团队保护,手艺支撑牢靠
- 4 ReactNative – Learn once, write anywhere: Build mobile apps with React
- 5 运用体式格局简朴,机能异常高,支撑服务端衬着
- 6 React异常火,从手艺角度,可以满足好奇心,进步手艺水平;从职业角度,有利于求职和提拔,有利于介入潜力大的项目
React中的中心观点
- 1 假造DOM(Virtual DOM)
- 2 Diff算法(假造DOM的加速器,提拔React机能的宝贝)
假造DOM(Vitural DOM)
React将DOM笼统为假造DOM,假造DOM实在就是用一个对象来形貌DOM,经由历程对照前后两个对象的差别,终究只把变化的部份从新衬着,进步衬着的效力
为何用假造dom,当dom反生变动时需要遍历 而原生dom可遍历属性多大231个 且大部份与衬着无关 更新页面价值太大
VituralDOM的处置惩罚体式格局
- 1 用 JavaScript 对象组织示意 DOM 树的组织,然后用这个树构建一个真正的 DOM 树,插到文档当中
- 2 当状况变动的时刻,从新组织一棵新的对象树。然后用新的树和旧的树举行比较,纪录两棵树差别
- 3 把2所纪录的差别运用到步骤1所构建的真正的DOM树上,视图就更新了
Diff算法
当你运用React的时刻,在某个时候点 render() 函数建立了一棵React元素树,
鄙人一个state或许props更新的时刻,render() 函数将建立一棵新的React元素树,
React将对照这两棵树的差别之处,计算出怎样高效的更新UI(只更新变化的处所)
<!-- 相识:
有一些处置惩罚将一棵树转换为另一棵树的最小操纵数算法题目的通用计划。然则,树中元素个数为n,最先进的算法 的时候庞杂度为O(n3) 。
假如直接运用这个算法,在React中展现1000个元素则需要举行10亿次的比较。这操纵太甚高贵,相反,React基于两点假定,完成了一个O(n)算法,提拔机能: -->
React中有两种假定:
- 1 两个差别范例的元素会发生差别的树(根元素差别组织树肯定差别)
- 2 开辟者可以经由历程key属性指定差别树中没有发生转变的子元素
Diff算法的申明 – 1
- 假如两棵树的根元素范例差别,React会烧毁旧树,建立新树
// 旧树
<div>
<Counter />
</div>
// 新树
<span>
<Counter />
</span>
实行历程:destory Counter -> insert Counter
Diff算法的申明 – 2
- 关于范例雷同的React DOM 元素,React会对照二者的属性是不是雷同,只更新差别的属性
- 当处置惩罚完这个DOM节点,React就会递归处置惩罚子节点。
// 旧
<div className="before" title="stuff" />
// 新
<div className="after" title="stuff" />
只更新:className 属性
// 旧
<div style={{color: 'red', fontWeight: 'bold'}} />
// 新
<div style={{color: 'green', fontWeight: 'bold'}} />
只更新:color属性
Diff算法的申明 – 3
- 1 当在子节点的背面增加一个节点,这时刻两棵树的转化事情实行的很好
// 旧
<ul>
<li>first</li>
<li>second</li>
</ul>
// 新
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
实行历程:
React会婚配新旧两个<li>first</li>,婚配两个<li>second</li>,然后增加 <li>third</li> tree
- 2 然则假如你在最先位置插进去一个元素,那末题目就来了:
// 旧
<ul>
<li>Duke</li>
<li>Villanova</li>
</ul>
// 新
<ul>
<li>Connecticut</li>
<li>Duke</li>
<li>Villanova</li>
</ul>
在没有key属性时实行历程:
React将转变每一个子删除从新建立,而非坚持 <li>Duke</li> 和 <li>Villanova</li> 稳定
key 属性
为相识决以上题目,React供应了一个 key 属性。当子节点带有key属性,React会经由历程key来婚配原始树和厥后的树。
// 旧
<ul>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
// 新
<ul>
<li key="2014">Connecticut</li>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
实行历程:
如今 React 晓得带有key '2014' 的元素是新的,关于 '2015' 和 '2016' 仅仅挪动位置即可
- 申明: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的注重点
注重 1: 假如在 JSX 中给元素增加类, 需要运用
className
替代 class- 相似:label 的 for属性,运用
htmlFor
替代
- 相似:label 的 for属性,运用
- 注重 2:在 JSX 中可以直接运用 JS代码,直接在 JSX 中经由历程 {} 中心写 JS代码即可
- 注重 3:在 JSX 中只能运用表达式,然则不能涌现 语句!!!
- 注重 4:在 JSX 中解释语法:
{/* 中心是解释的内容 */}
React组件
React 组件可以让你把UI分割为自力、可复用的片断,并将每一片断视为互相自力的部份。
- 组件是由一个个的HTML元素构成的
- 观点上来讲, 组件就像JS中的函数。它们接收用户输入(
props
),而且返回一个React对象,用来形貌展如今页面中的内容
React建立组件的两种体式格局
- 1 经由历程 JS函数 建立(无状况组件)
- 2 经由历程 class 建立(有状况组件)
函数式组件 和 class 组件的运用场景申明:
1 假如一个组件仅仅是为了展现数据,那末此时就可以运用 函数组件
2 假如一个组件中有肯定营业逻辑,需要操纵数据,那末就需要运用 class 建立组件,因为,此时需要运用 state
JavaScript函数建立
- 注重:1 函数称号必需为大写字母开首,React经由历程这个特征来推断是不是是一个组件
- 注重:2 函数必需有返回值,返回值可以是:JSX对象或
null
- 注重:3 返回的JSX,必需有一个根元素
- 注重:4 组件的返回值运用
()
包裹,防止换行题目
function Welcome(props) {
return (
// 此处解释的写法
<div className="shopping-list">
{/* 此处 解释的写法 必需要{}包裹 */}
<h1>Shopping List for {props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
</ul>
</div>
)
}
ReactDOM.render(
<Welcome name="jack" />,
document.getElementById('app')
)
class建立
在es6中class仅仅是一个语法糖,不是真正的类,本质上照样组织函数+原型 完成继续
// ES6中class关键字的简朴运用
// - **ES6中的一切的代码都是运转在严厉情势中的**
// - 1 它是用来定义类的,是ES6中完成面向对象编程的新体式格局
// - 2 运用`static`关键字定义静态属性
// - 3 运用`constructor`组织函数,建立实例属性
// - [参考](http://es6.ruanyifeng.com/#docs/class)
// 语法:
class Person {
// 实例的组织函数 constructor
constructor(age){
// 实例属性
this.age = age
}
// 在class中定义要领 此处为实例要领 经由历程实例办理挪用
sayHello () {
console.log('人人好,我本年' + this.age + '了');
}
// 静态要领 经由历程组织函数办理挪用 Person.doudou()
static doudou () {
console.log('我是小明,我新get了一个妙技,会暖床');
}
}
// 增加静态属性
Person.staticName = '静态属性'
// 实例化对象
const p = new Person(19)
// 完成继续的体式格局
class American extends Person {
constructor() {
// 必需挪用super(), super示意父类的组织函数
super()
this.skin = 'white'
this.eyeColor = 'white'
}
}
// 建立react对象
// 注重:基于 `ES6` 中的class,需要合营 `babel` 将代码转化为阅读器识别的ES5语法
// 装置:`npm i -D babel-preset-env`
// react对象继续字React.Component
class ShoppingList extends React.Component {
constructor(props) {
super(props)
}
// class建立的组件中 必需有rander要领 且显现return一个react对象或许null
render() {
return (
<div className="shopping-list">
<h1>Shopping List for {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
</ul>
</div>
)
}
}
给组件通报数据 – 父子组件通报数据
- 组件中有一个
只读的对象
叫做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
props
- 作用:给组件通报数据,平经常使用在父子组件之间
- 申明:React把通报给组件的属性转化为一个对象并交给
props
- 特征:
props
是只读的,没法给props
增加或修正属性 props.children
:猎取组件的内容,比方:-
<Hello>组件内容</Hello>
中的组件内容
-
// props 是一个包括数据的对象参数,不要试图修正 props 参数
// 返回值:react元素
function Welcome(props) {
// 返回的 react元素中必需只需一个根元素
return <div>hello, {props.name}</div>
}
class Welcome extends React.Component {
constructor(props) {
super(props)
}
render() {
return <h1>Hello, {this.props.name}</h1>
}
}
state
状况即数据
- 作用:用来给组件供应
组件内部
运用的数据 - 注重:只需经由历程
class
建立的组件才具有状况 - 注重:状况是私有的,完整由组件来掌握
注重:不要在
state
中增加render()
要领中不需要的数据,会影响衬着机能!- 可以将组件内部运用然则不衬着在视图中的内容,直接增加给 this
注重:不要在
render()
要领中挪用 setState() 要领来修正state
的值- 然则可以经由历程
this.state.name = 'rose'
体式格局设置state(不引荐!!!!)
- 然则可以经由历程
// 例:
class Hello extends React.Component {
constructor() {
// es6继续必需用super挪用父类的constructor
super()
this.state = {
gender: 'male'
}
}
render() {
return (
<div>性别:{ this.state.gender }</div>
)
}
}
JSX语法转化历程
// 1、JSX
const element = (
<h1 className="greeting">
Hello, world!
</h1>
)
// 2、JSX -> createElement
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
)
// React elements: 运用对象的情势形貌页面组织
// Note: 这是简化后的对象组织
const element = {
type: 'h1',
props: {
className: 'greeting',
},
children: ['Hello, world']
}
批评列表案例
- 稳固有状况组件和无状况组件的运用
- 两个组件:
<CommentList></CommentList>
和<Comment></Comment>
[
{ user: '张三', content: '哈哈,沙发' },
{ user: '张三2', content: '哈哈,板凳' },
{ user: '张三3', content: '哈哈,凉席' },
{ user: '张三4', content: '哈哈,砖头' },
{ user: '张三5', content: '哈哈,楼下山炮' }
]
// 属性扩大
<Comment {...item} key={i}></Comment>
style款式
// 1. 直接写行内款式:
<li style={{border:'1px solid red', fontSize:'12px'}}></li>
// 2. 抽离为对象情势
var styleH3 = {color:'blue'}
var styleObj = {
liStyle:{border:'1px solid red', fontSize:'12px'},
h3Style:{color:'green'}
}
<li style={styleObj.liStyle}>
<h3 style={styleObj.h3Style}>批评内容:{props.content}</h3>
</li>
// 3. 运用款式表定义款式:
import '../css/comment.css'
<p className="pUser">批评人:{props.user}</p>
相干文章
- React数据流和组件间的沟通总结
- 单向数据流和双向绑定各有什么优缺点?
- 怎样更好的明白假造DOM?
- React中文文档
- React 源码理会系列 - 难以想象的 react diff
- 深入浅出React(四):假造DOM Diff算法理会
组件的性命周期
- 简朴说:一个组件从最先到最后灭亡所阅历的种种状况,就是一个组件的性命周期
组件性命周期函数的定义:从组件被建立,到组件挂载到页面上运转,再到页面封闭组件被卸载,这三个阶段老是伴随着组件林林总总的事宜,那末这些事宜,统称为组件的性命周期函数!
- 经由历程这个函数,可以让开辟人员的代码,介入到组件的性命周期中。也就是说,经由历程钩子函数,就可以掌握组件的行动
- react component
- React Native 中组件的性命周期
- React 性命周期的治理艺术
- 智能组件和木偶组件
组件性命周期函数总览
- 组件的性命周期包括三个阶段:建立阶段(Mounting)、运转和交互阶段(Updating)、卸载阶段(Unmounting)
- Mounting:
constructor()
componentWillMount()
render()
componentDidMount()
- Updating
componentWillReceiveProps()
shouldComponentUpdate()
componentWillUpdate()
render()
componentDidUpdate()
- Unmounting
componentWillUnmount()
组件性命周期 – 建立阶段(Mounting)
- 特征:该阶段的函数只实行一次
constructor()
- 作用:1 猎取props 2 初始化state
- 申明:经由历程
constructor()
的参数props
猎取 - 设置state和props
class Greeting extends React.Component {
constructor(props) {
// 猎取 props
super(props)
// 初始化 state
this.state = {
count: props.initCount
}
}
}
// 初始化 props
// 语法:经由历程静态属性 defaultProps 来初始化props
Greeting.defaultProps = {
initCount: 0
};
componentWillMount()
- 申明:组件被挂载到页面之前挪用,其在render()之前被挪用,因而在这要领里
同步
地设置状况将不会触发重衬着 - 注重:没法猎取页面中的DOM对象
- 注重:可以挪用
setState()
要领来转变状况值 - 用处:发送ajax请求猎取数据
componentWillMount() {
console.warn(document.getElementById('btn')) // null
this.setState({
count: this.state.count + 1
})
}
render()
- 作用:衬着组件到页面中,没法猎取页面中的DOM对象
注重:不要在render要领中挪用
setState()
要领,否则会递归衬着- 缘由申明:状况转变会从新挪用
render()
,render()
又从新转变状况
- 缘由申明:状况转变会从新挪用
render() {
console.warn(document.getElementById('btn')) // null
return (
<div>
<button id="btn" onClick={this.handleAdd}>打豆豆一次</button>
{
this.state.count === 4
? null
: <CounterChild initCount={this.state.count}></CounterChild>
}
</div>
)
}
componentDidMount()
- 1 组件已挂载到页面中
- 2 可以举行DOM操纵,比方:猎取到组件内部的DOM对象
- 3 可以发送请求猎取数据
- 4 可以经由历程
setState()
修正状况的值 - 注重:在这里修正状况会从新衬着
componentDidMount() {
// 此时,就可以猎取到组件内部的DOM对象
console.warn('componentDidMount', document.getElementById('btn'))
}
组件性命周期 – 运转阶段(Updating)
- 特征:该阶段的函数实行屡次
- 申明:每当组件的
props
或许state
转变的时刻,都邑触发运转阶段的函数
componentWillReceiveProps()
- 申明:组件接收到新的
props
前触发这个要领 - 参数:当前组件
props
值 - 可以经由历程
this.props
猎取到上一次的值 - 运用:若你需要响应属性的转变,可以经由历程对照
this.props
和nextProps
并在该要领中运用this.setState()
处置惩罚状况转变 - 注重:修正
state
不会触发该要领
componentWillReceiveProps(nextProps) {
console.warn('componentWillReceiveProps', nextProps)
}
shouldComponentUpdate()
- 作用:依据这个要领的返回值决议是不是从新衬着组件,返回
true
从新衬着,否则不衬着 - 上风:经由历程某个前提衬着组件,下降组件衬着频次,提拔组件机能
- 申明:假如返回值为
false
,那末,后续render()
要领不会被挪用 - 注重:这个要领必需返回布尔值!!!
- 场景:依据随机数决议是不是衬着组件
// - 参数:
// - 第一个参数:最新属性对象
// - 第二个参数:最新状况对象
shouldComponentUpdate(nextProps, nextState) {
console.warn('shouldComponentUpdate', nextProps, nextState)
return nextState.count % 2 === 0
}
componentWillUpdate()
- 作用:组件将要更新
- 参数:最新的属性和状况对象
- 注重:不能修正状况 否则会轮回衬着
componentWillUpdate(nextProps, nextState) {
console.warn('componentWillUpdate', nextProps, nextState)
}
render() 衬着
- 作用:从新衬着组件,与
Mounting
阶段的render
是同一个函数 - 注重:这个函数可以实行屡次,只需组件的属性或状况转变了,这个要领就会从新实行
componentDidUpdate()
- 作用:组件已被更新
- 参数:旧的属性和状况对象
componentDidUpdate(prevProps, prevState) {
console.warn('componentDidUpdate', prevProps, prevState)
}
组件性命周期 – 卸载阶段(Unmounting)
- 组件烧毁阶段:组件卸载时期,函数比较单一,只需一个函数,这个函数也有一个明显的特征:组件一生只能实行顺次!
- 运用申明:只需组件不再被衬着到页面中,那末这个要领就会被挪用( 衬着到页面中 -> 不再衬着到页面中 )
componentWillUnmount()
作用:在卸载组件的时刻,实行清算事情,比方
- 1 消灭定时器
- 2 消灭
componentDidMount
建立的DOM对象
React – createClass(不引荐)
React.createClass({})
体式格局,建立有状况组件,该体式格局已被烧毁!!!- 经由历程导入
require('create-react-class')
,可以在不实用ES6的情况下,建立有状况组件 - getDefaultProps() 和 getInitialState() 要领:是
createReactClass()
体式格局建立组件中的两个函数 - React without ES6
- React 不实用ES6
var createReactClass = require('create-react-class');
var Greeting = createReactClass({
// 初始化 props
getDefaultProps: function() {
console.log('getDefaultProps');
return {
title: 'Basic counter!!!'
}
},
// 初始化 state
getInitialState: function() {
console.log('getInitialState');
return {
count: 0
}
},
render: function() {
console.log('render');
return (
<div>
<h1>{this.props.title}</h1>
<div>{this.state.count}</div>
<input type='button' value='+' onClick={this.handleIncrement} />
</div>
);
},
handleIncrement: function() {
var newCount = this.state.count + 1;
this.setState({count: newCount});
},
propTypes: {
title: React.PropTypes.string
}
});
ReactDOM.render(
React.createElement(Greeting),
document.getElementById('app')
);
state和setState
- 注重:运用
setState()
要领修正状况,状况转变后,React会从新衬着组件 - 注重:不要直接修正state属性的值,如许不会从新衬着组件!!!
- 运用:1 初始化state 2 setState修正state
// 修正state(不引荐运用)
// https://facebook.github.io/react/docs/state-and-lifecycle.html#do-not-modify-state-directly
this.state.test = '如许体式格局,不会从新衬着组件';
constructor(props) {
super(props)
// 准确姿态!!!
// -------------- 初始化 state --------------
this.state = {
count: props.initCount
}
}
componentWillMount() {
// -------------- 修正 state 的值 --------------
// 体式格局一:
this.setState({
count: this.state.count + 1
})
this.setState({
count: this.state.count + 1
}, function(){
// 因为 setState() 是异步操纵,所以,假如想马上猎取修正后的state
// 需要在回调函数中猎取
// https://doc.react-china.org/docs/react-component.html#setstate
});
// 体式格局二:
this.setState(function(prevState, props) {
return {
counter: prevState.counter + props.increment
}
})
// 或许 - 注重: => 背面需要带有小括号,因为返回的是一个对象
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}))
}
组件绑定事宜
- 1 经由历程React事宜机制
onClick
绑定 2 JS原生体式格局绑定(经由历程
ref
猎取元素)- 注重:
ref
是React供应的一个特别属性 -
ref
的运用申明:react ref
- 注重:
React中的事宜机制 – 引荐
- 注重:事宜称号采纳驼峰定名法
- 比方:
onClick
用来绑定单击事宜
<input type="button" value="触发单击事宜"
onClick={this.handleCountAdd}
onMouseEnter={this.handleMouseEnter}
/>
JS原生体式格局 – 晓得即可
- 申明:给元素增加
ref
属性,然后,猎取元素绑定事宜
// JSX
// 将当前DOM的援用赋值给 this.txtInput 属性
<input ref={ input => this.txtInput = input } type="button" value="我是豆豆" />
componentDidMount() {
// 经由历程 this.txtInput 属性猎取元素绑定事宜
this.txtInput.addEventListener(() => {
this.setState({
count:this.state.count + 1
})
})
}
事宜绑定中的this
- 1 经由历程
bind
绑定 - 2 经由历程
箭头函数
绑定
经由历程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
});
}
受控组件
在HTML当中,像
input
,
textarea
和
select
这类表单元素会保持自身状况,并依据用户输入举行更新。在React中,可变的状况一般保存在组件的
state
中,而且只能用
setState()
要领举行更新.React依据初始状况衬着表单组件,接收用户后续输入,转变表单组件内部的状况。
因而,将那些值由React掌握的表单元素称为:受控组件。
受控组件的特征:
- 1 表单元素
- 2 由React经由历程JSX衬着出来
- 3 由React掌握值的转变,也就是说想要转变元素的值,只能经由历程React供应的要领来修正
- 注重:只能经由历程setState来设置受控组件的值
// 模仿完成文本框数据的双向绑定
<input type="text" value={this.state.msg} onChange={this.handleTextChange}/>
// 当文本框内容转变的时刻,触发这个事宜,从新给state赋值
handleTextChange = event => {
console.log(event.target.value)
this.setState({
msg: event.target.value
})
}
批评列表案例
[
{name: '小明', content: '沙发!!!'},
{name: '小红', content: '小明,居然是你'},
{name: '小刚', content: '小明,放学你别走!!!'},
]
props校验
- 作用:经由历程范例搜检,进步顺序的稳定性
- 敕令:
npm i -S prop-types
- 范例校验文档
- 运用:给类供应一个静态属性
propTypes
(对象),来束缚props
// 引入模块
import PropTypes from 'prop-types'
// ...以下代码是类的静态属性:
// propTypes 静态属性的称号是牢固的!!!
static propTypes = {
initCount: PropTypes.number, // 划定属性的范例
initAge: PropTypes.number.isRequired // 划定属性的范例,且划定为必传字段
}
React 单向数据流
- React 中采纳单项数据流
- 数据活动方向:自上而下,也就是只能由父组件通报到子组件
- 数据都是由父组件供应的,子组件想要运用数据,都是从父组件中猎取的
- 假如多个组件都要运用某个数据,最好将这部份同享的状况提拔至他们近来的父组件当中举行治理
- 单向数据流
- 状况提拔
react中的单向数据活动:
1 数据应该是从上往下活动的,也就是由父组件将数据通报给子组件
2 数据应该是由父组件供应,子组件要运用数据的时刻,直接从子组件中猎取
在我们的批评列表案例中:数据是由CommentList组件(父组件)供应的
子组件 CommentItem 担任衬着批评列表,数据是由 父组件供应的
子组件 CommentForm 担任猎取用户输入的批评内容,终究也是把用户名和批评内容通报给了父组件,由父组件担任处置惩罚这些数据( 把数据交给 CommentItem 由这个组件担任衬着 )
组件通信
- 父 -> 子:
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组件
定义
运用步骤
- 1 导入路由组件
2 运用
<Router></Router>
作为根容器,包裹全部运用(JSX)- 在全部运用顺序中,只需要运用一次
- 3 运用
<Link to="/movie"></Link>
作为链接地点,并指定to
属性 - 4 运用
<Route path="/" compoent={Movie}></Route>
展现路由内容
// 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>
注重点
-
<Router></Router>
:作为全部组件的根元素,是路由容器,只能有一个唯一的子元素 -
<Link></Link>
:相似于vue中的<router-link></router-link>
标签,to
属性指定路由地点 -
<Route></Route>
:相似于vue中的<router-view></router-view>
,指定路由内容(组件)展现位置
路由参数
- 设置:经由历程
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)
fetch
- 作用:Fetch 是一个当代的观点, 等同于 XMLHttpRequest。它供应了许多与XMLHttpRequest雷同的功用,但被设想成更具可扩大性和高效性。
-
fetch()
要领返回一个Promise
对象
fetch 基础运用
/*
经由历程fetch请求返来的数据,是一个Promise对象.
挪用then()要领,经由历程参数response,猎取到响应对象
挪用 response.json() 要领,理会服务器响应数据
再次挪用then()要领,经由历程参数data,就猎取到数据了
*/
fetch('/api/movie/' + this.state.movieType)
// response.json() 读取response对象,并返回一个被理会为JSON花样的promise对象
.then((response) => response.json())
// 经由历程 data 猎取到数据
.then((data) => {
console.log(data);
this.setState({
movieList: data.subjects,
loaing: false
})
})
跨域猎取数据的三种经常使用体式格局
- 1 JSONP
- 2 代办
- 3 CORS
JSONP
- 装置:
npm i -S fetch-jsonp
- 应用
JSONP
完成跨域猎取数据,只能猎取GET请求 fetch-jsonp
- fetch-jsonp
- 限定:1 只能发送GET请求 2 需要服务端支撑JSONP请求
/* movielist.js */
fetchJsonp('https://api.douban.com/v2/movie/in_theaters')
.then(rep => rep.json())
.then(data => { console.log(data) })
代办
-
webpack-dev-server
代办设置以下: - 题目:webpack-dev-server 是开辟时期运用的东西,项目上线了就不再运用 webpack-dev-server
- 处置惩罚:项目上线后的代码,也是会布置到一个服务器中,这个服务器设置了代办功用即可(请求两个服务器中设置的代办划定规矩雷同)
// webpack-dev-server的设置
devServer: {
// https://webpack.js.org/configuration/dev-server/#devserver-proxy
// https://github.com/chimurai/http-proxy-middleware#http-proxy-options
// http://www.jianshu.com/p/3bdff821f859
proxy: {
// 运用:/api/movie/in_theaters
// 接见 ‘/api/movie/in_theaters’ ==> 'https://api.douban.com/v2/movie/in_theaters'
'/api': {
// 代办的目的服务器地点
target: 'https://api.douban.com/v2',
// https请求需要该设置
secure: false,
// 必需设置该项
changeOrigin: true,
// '/api/movie/in_theaters' 途径重写为:'/movie/in_theaters'
pathRewrite: {"^/api" : ""}
}
}
}
/* movielist.js */
fetch('/api/movie/in_theaters')
.then(function(data) {
// 将服务器返回的数据转化为 json 花样
return data.json()
})
.then(function(rep) {
// 猎取上面花样化后的数据
console.log(rep);
})
CORS – 服务器端合营
- 示例:NodeJS设置跨域
- 跨域资源同享 CORS 详解 – 阮一峰
// 经由历程Express的中心件来处置惩罚一切请求
app.use('*', function (req, res, next) {
// 设置请求头为许可跨域
res.header('Access-Control-Allow-Origin', '*');
// 设置服务器支撑的一切头信息字段
res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length, Authorization,Accept,X-Requested-With');
// 设置服务器支撑的一切跨域请求的要领
res.header('Access-Control-Allow-Methods', 'POST,GET');
// next()要领示意进入下一个路由
next();
});
redux
- 状况治理东西,用来治理运用中的数据
中心
Action:行动的笼统,视图中的每一个用户交互都是一个action
- 比方:点击按钮
Reducer:行动响应的笼统,也就是:依据action行动,实行响应的逻辑操纵,更新state
- 比方:点击按钮后,增加使命,那末,增加使命这个逻辑放到 Reducer 中
- 1 建立State
Store:
- 1 Redux运用只能有一个store
- 2
getState()
:猎取state - 3
dispatch(action)
:更新state
/* action */
// 在 redux 中,action 就是一个对象
// action 必需供应一个:type属性,示意当前行动的标识
// 其他的参数:示意这个行动需要用到的一些数据
{ type: 'ADD_TODO', name: '要增加的使命称号' }
// 这个行动示意要切换使命状况
{ type: 'TOGGLE_TODO', id: 1 }
/* reducer */
// 第一个参数:示意状况(数据),我们需要给初始状况设置默认值
// 第二个参数:示意 action 行动
function todo(state = [], action) {
switch(action.type) {
case 'ADD_TODO':
state.push({ id: Math.random(), name: action.name, completed: false })
return state
case 'TOGGLE_TODO':
for(var i = 0; i < state.length; i++) {
if (state[i].id === action.id) {
state[i].completed = !state[i].completed
break
}
}
return state
default:
return state
}
}
// 要实行 ADD_TODO 这个行动:
dispatch( { type: 'ADD_TODO', name: '要增加的使命称号' } )
// 内部会挪用 reducer
todo(undefined, { type: 'ADD_TODO', name: '要增加的使命称号' })
引荐人人运用Fundebug,一款很好用的BUG监控东西~