一、 react 事件绑定
如果传递一个函数名给一个变量,之后通过函数名()的方式进行调用,在方法内部如果使用this则this的指向会丢失
在JSX中传递的事件不是一个字符串,而是一个函数(如:onClick={this.handleClick}),此时onClick即是中间变量,所以处理函数中的this指向会丢失。解决这个问题就是给调用函数时bind(this),从而使得无论事件处理函数如何传递,this指向都是当前实例化对象。
事件绑定方式
- constructor 中直接绑定(推荐使用)
this.closeASbtn = this.closeASbtn.bind(this); - 函数生命方式
//此时this指向是当前实例对象
handleAdd = ()=> {
console.log(this)
this.setState({
count:5
})
} - 在JSX中绑定,每次点击都会绑定一次
<button onClick={this.handleClick.bind(this)}>有bind点击一下</button>
事件对象
vue
- vue 的事件对象是原生的
- 事件被挂载到当前元素
- 和DOM事件一样
react
- react 的事件对象是syntheticEvent 是组合对象,模拟出来DOM事件所有能力
- event.nativeEvent 是原生对象
- 所有的事件挂载到document上
- 和DOM事件不一样,和Vue事件也不一样
react 自定义传参
<button onClick={this.handleClick.bind(this,id,name)}>有bind点击一下</button>
接收时最后一个参数是event对象
二、 受控组件和非受控组件
受控组件
- 每当表单的状态发生变化时,都会被写入组件的state中
- 在受控组件中,组件渲染出的状态与他的value或checked prop 相对应
- react受控组件更新state的流程
<1> 通过在初始state中设置表单的默认值
<2> 每当表单的值发生变化时,调用onChange事件处理器
<3> 事件处理器通过合成对象e拿到改变后的状态,并更新应用的state
<4> SetState触发视图的重新渲染,完成表单组件值的更新 - 使用受控组件需要为每一个组件绑定一个change事件,并且定义一个事件处理器来同步表单值和组件的状态,某些情况可以使用一个事件处理器来处理多个表单域
- 在受控组件上指定 value 的 prop 可以防止用户更改输入
非受控组件
- 如果一个组件没有value prop就可以称为非受控组件
- 非受控组件是一种反模式,他的值不受state和props控制
- 通常需要为其添加ref prop来访问渲染后的DOM元素
三、父子组件通讯
状态提升
就是如果两个子组件需要利用对方的状态的话,那么这个时候我们就需要使用到状态提升,具体做法就是把两个子组件的状态写到他们的父组件中,然后父组件把状态传递到子组件的props中去,这样子组件也相当于有状态
父子组件传参
父传子
在父组件中,我们引入子组件,通过给子组件添加属性,来起到传参的作用,子组件可以通过props获取父组件传过来的参数
//父组件
import React from 'react'
import ChildCom from './childCom.js'
class ParentCom extends React.Component {
render() {
return (
<div>
<h1>父组件</h1>
<ChildCom content={'我是父级过来的内容'}/>
</div>
)
}
}
export default ParentCom;
//子组件
import React from 'react'
class ChildCom extends React.Component {
render() {
return (
<div>
<h2>子组件</h2>
<div>
{this.props.content}
</div>
</div>
)
}//欢迎加入全栈开发交流群一起学习交流:864305860
}
export default ChildCom;
子传父
// 父组件
import React from 'react'
import ChildCom from './childCom.js'
class ParentCom extends React.Component {
state = {
getChildValue: ''
}
getChildValue(value) {
this.setState({
getChildValue: value
})
}
render() {
return (
<div>
<h1>父组件</h1>
<div>子组件过来的值为:{this.state.getChildValue}</div>
<ChildCom onValue={this.getChildValue.bind(this)}/>
</div>
)
}
}
export default ParentCom;
//子组件
import React from 'react'
class ChildCom extends React.Component {
valueToParent(value) {
this.props.onValue(value);
}
render() {
return (
<div>
<h2>子组件</h2>
<div>
<a onClick={this.valueToParent.bind(this,123)}>向父组件传值123</a>
</div>
</div>
)
}
}
export default ChildCom;
子组件向父组件传参,其实就是在父组件中给子组件添加一个属性,这个属性的内容为一个函数,然后在子组件中调用这个函数,即可达到传递参数的效果
四、setState 为何使用不可变的值
- 不可变值
可以用 this.state.arr.concat(100) 这样不会改变原来的数组arr,r如果用push就会改变原来的值,之所以这样做是因为在shouldCompomentUpdate 生命周期中,将要改变的值与之前的值做个比较来确定是否改变视图,以这种方式来优化性能 - 可能会异步更新
直接使用setState 是异步的
this.setState({
count:this.state.count + 1
},()=>{
console.log("count")
})
在setTimeout中使用是同步的
setTimeOut(()=>{
this.setState({
count:this.state.count +1
})
})
自己定义的DOM事件是同步的
document.body.addEventListener('click',()=>{
this.setState({
count:this.state.count +1
})
})
- 可能会被合并
setState 异步更新(类似object.assign()),更新之前会被合并
传入对象会被合并
this.setState({
count:this.state.count +1
})
this.setState({
count:this.state.count +1
})
this.setState({
count:this.state.count +1
})
传入函数不会被合并,执行结果+3
this.setState((prevState, props)=>{
return {
count:this.state.count +1
}
})
this.setState((prevState, props)=>{
return {
count:this.state.count +1
}
})
this.setState((prevState, props)=>{
return {
count:this.state.count +1
}
})
五、 react 生命周期
挂载、渲染、卸载
- componentWillMount加载前
- componentDidMount,加载完成
- componentWillReceiveProps (nextProps),在接受父组件改变后的props需要重新渲染组件时用到的比较多
- shouldComponentUpdate(nextProps,nextState),主要用于性能优化,唯一用于控制组件重新渲染的生命周期
- .componentWillUpdate (nextProps,nextState),shouldComponentUpdate返回true以后,组件进入重新渲染的流程,进入componentWillUpdate,这里同样可以拿到nextProps和nextState。
- componentDidUpdate(prevProps,prevState),组件更新完毕
- componentWillUnmount () 组件的卸载和数据的销毁
六、 高级特性
1.函数组件
- 纯函数,输入props,输出JSX
- 没有实例,没有生命周期,没有state
- 不能扩展其他方法
2. 非受控组件
- ref
- defalutValue,defalutChecked
- 手动获取DOM元素
使用场景
- 必须手动操作DOM,setState实现不了
- 文件上传 <input type="file">
- 某些富文本编辑器,需要传入DOM
受控组件和非受控组件
- 优先使用受控组件,符合react设计原则(数据驱动视图)
- 必须操作DOM,再使用非受控组件
3. portals 传送门
- 组件默认会按照既定层次嵌套渲染
- 如何让组件渲染到父组件以外
ReactDOM.createPortal(<div className="model">Model内容</div>,document.body)
使用场景
- 父组件设置overflow:hidden
- 父组件z-index太小
- fixed 需要放在body第一层级
4. react context(上下文)
使用场景
- 公共信息如何传递给每个组件
- 用props 太繁琐
- 用redux 小题大作
如何使用:
- 创建一个上下文容器
const {Provider, Consumer} = React.createContext(defaultValue); - provider用于生产共享数据的地方
<Provider value={/共享的数据/}>
/里面可以渲染对应的内容/
</Provider> - consumer,专门消费供应商产生的数据
5. 异步组件
- import
- react.lazy
- React.Suspense
网友评论