组件通讯
组件中props
函数组件通过参数props接收数据
类组件通过this.props获取
特点:
-
可以给组件传递任意类型的数据
-
props是只读属性,不能对值进行修改
-
注意:使用类组件时,如果写了构造函数,应该将props传递给super(),否则,无法在构造函数中获取到props,其他的地方是可以拿到的
父传子
-
父组件提供要传递的state数据
-
给子组件标签添加属性,值为state中的数据
-
子组件中通过props接收父组件中传递的数据
子传父
-
利用回调函数,父组件提供回调,子组件调用,将要传递的数据作为回调函数的参数
-
父组件提供一个回调函数,用来接收数据
-
将该函数作为属性的值,传递给子组件
-
子组件通过props调用回调函数
兄弟传值
-
将共享状态(数据)提升到最近的公共父组件中,由公共父组件管理这个状态
-
这个称为状态提升
-
公共父组件职责:1. 提供共享状态 2.提供操作共享状态的方法
-
要通讯的子组件只需要通过props接收状态或操作状态的方法
Context
作用: 跨组件传递数据
const { Provider, Consumer } = React.createContext()
<Provider value='pink'>
<div><Child /></div>
</Provider>
const Child1 = (props) => {
return (<div>我是第二代<Sun /></div>)
}
const Sun = () => {
return (<Consumer>{data => <div>我是第三代{ data}</div>}</Consumer>)
}
children属性
-
children属性: 表示组件标签的子节点,当组件标签有子节点时,props就会有该属性
-
children属性与普通的props一样,值可以使任意值(文本、react元素、组件、甚至是函数)
props校验
使用步骤
- 安装包
prop-types (yarn add prop-types | npm i props-types) - 导入prop-types 包
- 使用
组件名.propTypes={}来给组件的props添加校验规则 - 校验规则通过PropTypes对象来指定
常见的约束规则
- 创建的类型:
array、bool、func、number、object、string - React元素类型:
element - 必填项:
isRequired - 特定结构的对象:
shape({})
props的默认值
组件名.defaultProps={变量名:值}
组件的生命周期
创建时(挂载阶段)
- 执行时机:组件创建时(页面加载时)
- 执行顺序 constructor() --> render()--->componentDidMount()
更新时
执行时机:setState()、 forceUpdate()、 组件接收到新的props
说明:以上三者任意一种变化,组件就会重新渲染
执行顺序:
卸载时
执行时机:组件从页面中消失
作用:用来做清理操作
render-props模式
- 创建Mouse组件,在组件中提供复用的逻辑代码
- 将要复用的状态作为 props.children(state)方法的参数,暴露到组件外部
- 使用props.children() 的返回值作为要渲染的内容
高阶组件
- 创建一个函数,名称约定以with开头
- 指定函数参数,参数应该以大写字母开头
- 在函数内部创建一个类组件,提供复用的状态逻辑代码,并返回
- 在该组件中,渲染参数组件,同时将状态通过prop传递给参数组件
- 调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面 包装函数
// 定义一个函数,在函数内部创建一个相应类组件
function withMouse(WrappedComponent) {
// 该组件提供复用状态逻辑
class Mouse extends React.Component {
state = {
x: 0,
y: 0
}
// 事件的处理函数
handleMouseMove = (e) => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
// 当组件挂载的时候进行事件绑定
componentDidMount() {
window.addEventListener('mousemove', this.handleMouseMove)
}
// 当组件移除时候解绑事件
componentWillUnmount() {
window.removeEventListener('mousemove', this.handleMouseMove)
}
render() {
// 在render函数里面返回传递过来的组件,把当前组件的状态设置进去
return <WrappedComponent {...this.state} />
}
}
return Mouse
}
哪个组件需要加强,通过调用withMouse这个函数,然后把返回的值设置到父组件中即可
function Position(props) {
return (
<p>
X:{props.x}
Y:{props.y}
</p>
)
}
// 把position 组件来进行包装
let MousePosition = withMouse(Position)
class App extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<div>
高阶组件
<MousePosition></MousePosition>
</div>
)
}
}
设置displayName
- 使用高阶组件存在的问题:得到两个组件的名称相同
- 原因:默认情况下,React使用组件名称作为
displayName - 解决方式:为高阶组件设置
displayName,便于调试时区分不同的组件 displayName的作用:用于设置调试信息(React Developer Tools信息)- 设置方式:
传递props
- 问题:如果没有传递props,会导致props丢失问题
- 解决方式: 渲染
WrappedComponent时,将state和props一起传递给组件
小结
- 组件通讯是构建React应用必不可少的一环
- props的灵活性让组件更加强大
- 状态提升是React组件的常用模式
- 组件生命周期有助于理解组件的运行过程
- 钩子函数让开发者可以在特定的时机执行某些功能
render props模式和高阶组件都可以实现组件状态逻辑的复用- 组件极简模型:
(state,props) => UI