React组件进阶

314 阅读4分钟

组件通讯

组件中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()

image.png

更新时

执行时机:setState()、 forceUpdate()、 组件接收到新的props

说明:以上三者任意一种变化,组件就会重新渲染

执行顺序: image.png

卸载时

执行时机:组件从页面中消失

作用:用来做清理操作

image.png

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信息)
  • 设置方式: image.png

传递props

  • 问题:如果没有传递props,会导致props丢失问题
  • 解决方式: 渲染WrappedComponent时,将state和props一起传递给组件 image.png

小结

  • 组件通讯是构建React应用必不可少的一环
  • props的灵活性让组件更加强大
  • 状态提升是React组件的常用模式
  • 组件生命周期有助于理解组件的运行过程
  • 钩子函数让开发者可以在特定的时机执行某些功能
  • render props 模式和高阶组件都可以实现组件状态逻辑的复用
  • 组件极简模型: (state,props) => UI