属性
属性和状态是react中数据传递的载体
组件接收属性值的传递:
this.props.属性名
例如:
<Header title="留言" />
var Header = React.createClass({
render: function() {
return (<h2>{this.props.title}</h2>);
}
});
2、属性传递的方式
1、key-value形式
2、展开式传入
3、内部声明getDefaultProps
4、es6 使用 组件. defaultProps --- 构造器(this.props.xxx)
状态
React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。
React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
重要的方法:
getInitialState :定义初始状态 / es6 在constructor 中 通过this .state={} 设置
this.state :读取状态
this.setState:更新组件的状态 /es6中 在事件中调用需要在构造器中 通过bind绑定this
状态修改 组件会发生二次渲染 react组件中的render方法会重新执行
数据流
1、数据从父组件流向子组件
2、子组件数据流向父组件
双向绑定的数据流:
父传子:将父组件的内容用setState赋值给state,通过给添加属性name={this.state.str},子组件接收用this.props.name
子传父:给子组件添加一个点击事件,使用this.props属性,即this.props.name(this.refs.ipt.value),给父组件中的,父组件接收数据{this.state.str}
操作dom
ref获取dom元素 ref给dom添加该属性
通过this.refs.ref的值获取dom
父传子:
class Demo extends React.Component{
constructor(props){
super(props)
this.state={
str:''
}
}
tap(){
// console.log(this.refs.ipt.value)
this.setState({str:this.refs.ipt.value})
}
render(){
return(
<div>
<h1>父组件</h1>
<input type="text" ref="ipt"/>
<button onClick={this.tap.bind(this)}>发送给子组件</button>
<hr/>
<Child name={this.state.str}/>
</div>
)
}
}
class Child extends React.Component{
constructor(props){
super(props)
}
render(){
console.log(this.props)
return(
<div>
<h1>子组件</h1>
<p>接受父组件的数据--{this.props.name}</p>
</div>
)
}
}
ReactDOM.render(<Demo/>,document.getElementById('out'))
React ES6的写法
state的初始化和方法的this指针修正
推荐放在构造器里面书写
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.state = {items: [], text: ''};
}
事件传参
onClick={this.tap.bind(this,index)}
数据批量循环展示
使用jsx数组模版
补充内容:
state的改变会导致组件的二次渲染
讲文本框的类型设置成state 按钮的文字也设置成state
先将state绑定到页面上
点击的时候去改变state的值
反向传递—面试题
双向数据绑定
实现从zi组件传递到父组件
将子组件中变化的数据传递到父组件中
回调函数:当某个行为执行成功的时候另外一个行为立马触发
父子传值:
class Demo extends React.Component{
constructor(props){
super(props)
this.state={
str:''
}
}
render(){
var _this=this;
return(
<div>
<h1>父组件</h1>
<p>接收子组件发送的数据--{this.state.str}</p>
<hr/>
<Child name={function(msg){
_this.setState({str:msg})
}}/>
</div>
)
}
}
class Child extends React.Component{
constructor(props){
super(props)
}
tap(){
// this.props.name == function
// this.props.name() == function()
// this.props.name(a) == function(msg)
this.props.name(this.refs.ipt.value)
}
render(){
return(
<div>
<h1>子组件</h1>
<input type="text" ref="ipt"/>
<button onClick={this.tap.bind(this)}>发送给父组件</button>
</div>
)
}
}
ReactDOM.render(<Demo/>,document.getElementById('out'))
React生命周期
1、react组件的生命周期
a、生命周期指的是组件从初始化开始到结束的过程 或者是生命周期是描述ract组件从开始到结束的过程
b、每个react组件都具有生命周期
c、react都对组件通过生命周期给予的钩子函数进行管理
2、钩子函数
指的是系统某些状态和参数发生改变的时候,系统立马去通知对应处理的函数 叫做钩子函数
一方面又变动,另一方面立马去处理
3、react组件经历总体阶段
重点内容
a、mounted阶段 加载阶段 或者说初始化阶段 这个阶段组件由jsx转换成真实dom
b、update阶段 组件运行中阶段 或者更新阶段 当组件修改自身状态,或者父组件修改子组件属性的时候发生的阶段
c、unmount阶段 组件卸载阶段 这个一般是组件被浏览器回收的阶段
vue卸载指的是实例的解绑,而react的解绑是就是销毁了,浏览器中是找不到的
生命周期整体流程:
1.实例化
getDefaultProps 取得默认属性
getInitialState 初始化状态
componentWillMount 即将进入dom
render 描画dom
componentDidMount 已经进入dom
2、具体的声明函数周期—运行中阶段 数据更新过程
运行中阶段只有在父组件修改了子组件的属性或者说一个组件修改自身的状态才会发生的情况
a、组件将要接受新值componentWillReceiveProps(已加载组件收到新的参数时调用)//参数为最新更新的数据
b、组件是否更新 shouldComponentUpdate (影响整个项目的性能,决定视图的更新) 只能为true时后面的钩子函数才会执行
c、组件即将更新 componentWillUpdate
d、必不可少的render
e、组件更新完毕时运行的函数 componentDidUpdate
3、销毁时 componentWillUnmount
卸载组件
ReactDOM.unmountComponentAtNode(‘节点’)
虚拟dom与diff算法
Web界面由DOM树来构成,当其中某一部分发生变化时,其实就是对应的某个DOM节点发生了变化。在React中,构建UI界面的思路是由当前状态决定界面。前后两个状态就对应两套界面,然后由React来比较两个界面的区别,这就需要对DOM树进行Diff算法分析
diff算法:
传统:找到两棵任意的树之间最小的修改是一个复杂度为 O(n^3) 的问题. 因为需要不同的层级。
Facebook算法:
1.React 用了一种简单但是强大的技巧, 达到了接近 O(n) 的复杂度.
把树按照层级分解
2.列表比较,写一个 key 属性帮助 React 来处理它们之间的对应关系.实际中, 在子元素中找到唯一的 key 通常很容易.
3.Components比较,React app 通常由用户定义的 component 组合而成,通常结果是一个主要是很多 div 组成的树.这个信息也被 React 的 diff 算法考虑进去, React 只会匹配相同类型(ES6 class)的 component.
4.合并操作,当调用 component 的 setState 方法的时候, React 将其标记为 dirty.到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制.
5.选择性子树渲染,在组件上实现下面的方法
boolean shouldComponentUpdate(object nextProps, object nextState)
根据 component 的前一个和下一个 props/state,你可以告诉 React 这个 component 没有更新, 也不需要重新绘制.实现得好的话, 可以带来巨大的性能提升.
简言之:
(1)把树形结构按照层级分解,只比较同级元素。
(2)把列表结构的每个单元添加唯一的key属性,方便比较。
(3)React只会匹配相同的class的component(这里的class指的是组件名)。
(4)合并操作,调用component的setState方法的时候,React将其标记为dirty,到每个事件循环结束,React检查所有标记dirty的component重新绘制。
(5)选择性子树渲染。开发人员可以重写shouldComponentUpdate提高diff的性能
(http://segmentfault.com/a/1190000000606216)
前端工程师:最接近用户体验
数据加载
1、数据绑定的第一种方式:基于jsx绑定
1.在componentWillMount / componentDidMount 中获取ajax数据 ( 面试题)
2、将得到的数据存入state中
3、在render中直接将state中的数据循环遍历 放在一个jsx的数据模板中
4、循环叠加这个jsx模板 通过{}嵌入到页面中
2、mixins函数(es6 弃用)(存放公共变量的函数)
1、作用是可以将一些公共的方法写在一个object的方法里面
2、然后通过mixins在组件中声明这个对象的表达式
3、在jsx中 就可以使用this去调用object里面的各个方法
这样实现了react多个组件之间共享一些公共的方法
动画
css3动画
关键帧动画
animation @keyframes过渡动画 transition
javascript动画
各种库的动画方法,例如:JQ的animate方法
ReactTransition:React官方提供的动画解决方案
官方文档:https://facebook.github.io/react/docs/animation.html
ReactTransition使用方法:
引入组件
import ReactCSSTransitionGroup from ‘react-addons-css-transition-group‘
- 使用ReactCSSTransitionGroup标签包裹动画标签
<ReactCSSTransitionGroup
transitionName="example"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}>
{items}
</ReactCSSTransitionGroup>
注意:生成{items}的时候,里面每一个元素必须包含key属性。因为r**eact要判断哪个元素进入,停留,移除**
写动画用的css(斜体的字是上一页中的transitionName)
.example-enter 进入动画的起点
.example-enter-active 进入动画的终点.example-leave 离开动画的起点
.example-leave-active 离开动画的终点
定制动画的class
<ReactCSSTransitionGroup
transitionName={ {
enter: 'enter',
enterActive: 'enterActive',
leave: 'leave',
leaveActive: 'leaveActive',
appear: 'appear',
appearActive: 'appearActive'
} }>
{item}
</ReactCSSTransitionGroup>