react 组件进阶
目标:1.能够使用props接收数据
2.能够实现父子组建之间的通讯
3.能够实现兄弟组建之间的通讯
4.能够给组建添加props校验
5.能够说出生命周期常用的钩子函数
6.能够知道高阶组件的作用
一,组件通讯介绍
组件是独立且封闭的单元,默认情况下,只能使用组件自己的数据。在组件化过程中,我们将一个完整的功能拆分成多个组件,以更好的完成整个应用的功能,而在这个过程中,多个组件之间不可避免的要共享某些数据。为了实现这些功能,就需要打破组建的独立封闭性,让其与外界沟通,这个过程就是组件通讯。
二,组件的props
组建是封闭的,要接受外部数据应该通过props来实现
props的作用:接收传递给组件的数据
传递数据:给组件标签添加属性
接收数据:函数组件通过参数props接收数据,类组件通过this.props接受数据
组件的特点:
1.可以给组件传递任意类型的数据
2.props 是只读的对象,只能读取属性的值,无法修改对象
3.注意:使用类组建时,如果写了构造函数,应该将props传递给super(),否在无法在构造函数中获取到props。
三,组建通讯的三种方式
1.父组件 -> 子组件
1.父组件提供眼传递的state数据
2.给子组件标签添加属性,值为state 中的数据
3.子组件中通过props 接收父组建中传递的数据
2.子组件 -> 父组件
思路:利用回调函数,父组件提供回调,子组件调用,将要传递的数据作为回调函数的参数。
1.父组件提供一个回调函数(用于接受数据)
2.将该函数作为属性的值,传递给子组件
3.兄弟组件
将共享状态提升到最近的公共父组件中,由公共父组件管理这个状态
思路:状态提升
公共父组件职责,1,提供共享状态 2,提供操作共享状态的方法
要通讯的子组建只需要通过 props 接收状态或操作状态的方法
四,Context
思考:App组件要传递数据给Child 组件,该如何处理?
更好的姿势:使用 Context
作用:跨组件传递数据(比如:主题,语言等)
使用步骤:
1.调用React.createContext() 创建Provider(提供数据)和 Consumer (消费数据)两个组件
2.使用 Provider 组件作为父节点
3.设置value 属性,表示要传递的数据
4.调用Consumer 组件接收数据。
总结:
1.如果两个组件是远方亲戚(比如:嵌套多层)可以使用Context实现通讯
2.Context 提供李两个组件:Provider 和 Consumer
3.Provider 组件:用来提供数据
4.Consumer组建:用来消费数据
五,props深入
1.children 属性:表示组建标签的子节点。当组件标签有子节点时,props 就会有该属性
children 属性与普通的props一样,值可以是任意值(文本,React元素,组件,甚至是函数)
2.props校验
props校验:允许在创建组建的时候,就指定props的类型,格式等
使用步骤:
1) 安装包:prop-types(yarn add prop-types/npm i prop-types)
2) 导入包 prop-types 包
3)使用组件名.propTypes = {} 来给组件的props添加校验规则
4)校验规则通过PropTypes 对象来指定
约束规则 propType
1)常见类型:array,bool,func,number,object,string
2) React元素类型:element
3)必填项:isRequired
4) 特定结构的对象:shape({})
App.propType = {
color:PropTypes.array
}
props 默认值
场景:分页组建 -> 每夜展示条数
作用:给props 设置默认值,在未传入 props 是生效
六,组件的生命周期
概述:组件的生命周期有助于理解组件的运行方式、完成更复杂的组建功能、分析组件错误原因等。
组件的生命周期:组件从被创建到挂载到页面中运行,再到组建不用时卸载的过程。
生命周期的每个阶段总是伴随着一些方法调用,这些方法就是生命周期的钩子函数。
只有类组件才有生命周期。函数组件没有生命周期。
生命周期的三个阶段:
1.每个阶段的执行时机
2.每个阶段钩子函数的执行顺序
3.每个阶段钩子函数的作用
1.创建时:挂载阶段
执行时机:组建创建时(页面加载时)
执行顺序:construcor() ->render() -> componentDidMount()
2.更新时:(更新阶段)
执行时机:1.setState() 2.forceUpdate() 3.组件接收到新的props
说明:以上三着任意一种变化,组件就会重新渲染
render() -> componentDidMount()
3.卸载时:(卸载阶段)
执行时机:组件从页面消失
新版完整生命周期钩子函数:
七.props和高阶组件概述
如果两个组件中的部分功能相似或相同,该如何处理?
处理方式:复用相似的功能(联想函数封装)
复用 1.state 2.操作state的方法(组件状态逻辑)
两张方式:1.render props 模式 2.高阶组件(HOC)
注意:这两种方式不是新的API,而是利用React 自身特点的编码技巧,演化而成的固定模式
思路分析:
思路:将要复用的 state 和操作 state 的方法封装到一个组件中
问题1:如何拿到该组件中复用的state?
在使用组件时:添加一个值为函数的prop,通过函数参数来获取(需要组价内部实现)
问题2:如何渲染任意的UI?
使用该函数的返回值作为要渲染的UI 内容(需要组件内部实现)
<Mouse render={(mouse) =>{}} />
<Mouse redner ={(mouse)=>(
<p>鼠标当前位置 {mouse.x},{mouse.y}</p>
)}/>
使用步骤
1.创建Mouse组件,在组件中提供复用的状态逻辑代码(1.状态 2.操作状态的方法)
2.将要复用的状态作为 props.render(state)方法的参数,暴露到组件外部
3.将使用props.render()的返回值作为要渲染的内容
class Mouse extends React.Component {
// ...省略state和操作state的方法
render(){
return this.props.render(this.state)
}
}
<mouse render={(mouse) =><p>鼠标当前位置{mouse.x},{mouse.y} </p>} />
演示Mouse 组件的复用
Mouse组件负责:封装复用的状态逻辑代码(1.状态 2.操作状态的方法)
状态:鼠标坐标(x,y)
操作状态的方法:鼠标移动事件
传入的render prop负责:使用复用的状态来渲染UI结构
children 代替render属性
注意:并不是该模式叫 render props 就必须使用名为render 的prop,世界上可以使用任意名称的prop
把prop 是一个函数并且告诉组件要渲染什么内容的技术叫做:render props模式
推荐:使用 children 代替 render 属性
<Mouse>
{({x,y}) => <p>鼠标的位置是 {x} ,{y} </p>}
</Mouse>
//组件内部
this.props.children(this.state)
代码优化
1.推荐:给 render props 模式添加 props 校验
2.应该在组件卸载是解除mousemove 事件绑定
Mouse.propTypes = {
children:PropTypes.func.isRequired
}
componentYillUnmount(){
window.removeEventListener('mousemove',this.handleMouseMove)
}