多个组件之间进行数据共享就叫做组件通讯。
组件通讯通过props和context来实现
props是用于接受外部传递给组件的数据。
props是通过给标签添加属性的方式来床底数据。
在函数组件中通过props参数接受,类组件中通过this.props来接收,props是一个对象。
React允许在创建组件时指定props属性的类型和格式,可以在传入的数据格式错误时抛出错误信息。
- 安装prop-types包
cnpm i props-types
- 导入对应的包
import PropTypes from 'prop-types'
- 使用组件名.PropTypes来添加校验规则
App.PropTypes = {colors: PropTypes.array}
array bool func number object string symbol
在设置属性后再添加一项isRequired属性设置为必填项
getArc: PropTypes.func.isRequired
option: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
})
组件名.defaultProps = {
pageSize: 10
}
如果父子的嵌套层次很深,可以通过context跨层次传递。
const { Provider , Consumer } =
React.createContext();
<Provider>
<div></div>
</Provider>
<Provider value='pink'>
<div></div>
</Provider>
<Consumer>
(data) => <span>这里是数据:{data}</span>
</Consumer>
组件的复用其实就是复用state和setState,有renderprops和高阶组件两种模式来实现复用。
思路:将state和操作state的方法封装到组件中。
添加一个函数作为props,用这个函数来将组件内部的值公开,通过这个函数的返回值来渲染UI
刚才是显示鼠标的坐标,这个组件还可以在鼠标位置显示图片充当特殊指针
这种方式可以实现逻辑的复用,但不能复用UI
App.propTypes = {
children: PropTypes.func.isRequired
}
// 卸载组件时解除事件
componentWillUnmount(){
window.removeEventListener('mousemove',this.changeMouse)
}
高阶组件(HOC)实际上是一个函数,接收一个组件,返回一个增强后的组件。
函数内部提供一个类组件,这个类组件提供可以复用的逻辑代码,通过props将其传递给传入函数的组件。
// 高阶组件函数
function withMouse (Com) {
class App extends React.Component {
state = {
x: 0,
y: 0
}
// 鼠标事件
changeMouse = (e) => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
// 在生命周期中绑定事件
componentDidMount(){
window.addEventListener('mousemove',this.changeMouse)
}
// 卸载组件时解除事件
componentWillUnmount(){
window.removeEventListener('mousemove',this.changeMouse)
}
// render
render(){
return (<Com {...this.state}></Com>);
}
}
return App;
}
// 函数组件
const Mouse = props => (
<h1>
<div>x: {props.x}</div>
<div>y: {props.y}</div>
</h1>
)
// 调用高阶组件函数
const StrongMouse = withMouse(Mouse)
被高阶组件包装的组件在devtools中会显示原始的组件名(高阶组件函数return时的名称),不利于调试。
// 高阶组件函数
function withMouse (Com) {
class App extends React.Component {
state = {
x: 0,
y: 0
}
// 鼠标事件
changeMouse = (e) => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
// 在生命周期中绑定事件
componentDidMount(){
window.addEventListener('mousemove',this.changeMouse)
}
// 卸载组件时解除事件
componentWillUnmount(){
window.removeEventListener('mousemove',this.changeMouse)
}
// render
render(){
return (<Com {...this.state}></Com>);
}
}
// 设置displayName
App.displayName = `WithApp${getDiaplayName(Com)}`
return App;
}
// 设置displayName的辅助函数,通用
function getDisplayName (Com) {
return Com.displayName || Com.Name || 'Component'
}
上面的代码中,在高阶组件函数的返回值上直接添加属性是加不上去的,因为这个时候props已经丢失了
需要在渲染组件时,将state和props一起传递下去
// 高阶组件函数,最终版本,新增加了props传递
function withMouse (Com) {
class App extends React.Component {
state = {
x: 0,
y: 0
}
// 鼠标事件
changeMouse = (e) => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
// 在生命周期中绑定事件
componentDidMount(){
window.addEventListener('mousemove',this.changeMouse)
}
// 卸载组件时解除事件
componentWillUnmount(){
window.removeEventListener('mousemove',this.changeMouse)
}
// render
render(){
return (<Com {...this.state} {...this.props}></Com>);
}
}