render props

状态逻辑复用

如何向组件内部动态传入带内容的结构(标签)?

Vue中:
使用slot技术, 也就是通过组件标签体传入结构 <A><B/></A>

React中: react没有插槽
使用children propsrender props : 通过组件标签属性传入结构,而且可以携带数据

render props - 不推荐

image.png

  1. <A render={(data) => <C data={data}></C>}></A>
  2. A组件: {this.props.render(内部state数据)}
  3. C组件: 读取A组件传入的数据显示 {this.props.data}

import React, { Component } from 'react'

export default class Parent extends Component {
    render() {
        return (
            <div className="parent">
                <h3>我是Parent组件</h3>
                <A render={(name)=><B name={name}/>}/>
            </div>
        )
    }
}

class A extends Component {
    state = {name:'tom'}
    render() {
        const {name} = this.state
        return (
            <div className="a">
                <h3>我是A组件</h3>
                {this.props.render(name)}
            </div>
        )
    }
}

children props -推荐children代替render

class Child extends Component{
    render(){
        return <div>
            {this.props.children[1]} //22222222
            {this.props.children[2]} //33333333
            {this.props.children[0]} //11111111
        </div>
    }
}
export default class App extends Component {
    render() {
        return (
            <div>
                <Child>
                    <div>11111111</div>
                    <div>22222222</div>
                    <div>33333333</div>
                </Child>
            </div>
        )
    }
}

传参

import React, { Component } from 'react'

export default class Parent extends Component {
    render() {
        return (
            <div className="parent">
                <h3>我是Parent组件</h3>
        <A>
              {
                  data=>{return <p>{data.name}</p> 这里也可以是组件}
              }
        </A>
            </div>
        )
    }
}

class A extends Component {
  state = {name:'tom'};
    render() {
        return (
            <div className="a">
                <h3>我是A组件</h3>
        {this.props.children(this.state)}
            </div>
        )
    }
}

添加props校验

import PropTypes from 'prop-types';

class A ...;
// 添加对应的props校验
A.propTypes = {
  //render: PropTypes.func.isRequired,
  //children: PropTypes.func.isRequired
}

高阶组件 - withHOC

状态逻辑复用
image.png

代码示例

image.png

// 创建高阶组件
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() {
      return <WrappedComponent {...this.state} />
    }
  }

  return Mouse
}

// 用来测试高阶组件
const Position = props => (
  <p>
    鼠标当前位置:(x: {props.x}, y: {props.y})
  </p>
)

// 获取增强后的组件:
const MousePosition = withMouse(Position)

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>高阶组件</h1>
        {/* 渲染增强后的组件 */}
        <MousePosition />
      </div>
    )
  }
}

设置组件名 displayName

image.png

// 创建高阶组件
function withMouse(WrappedComponent) {
  // 该组件提供复用的状态逻辑
  class Mouse extends React.Component {
    ...
  // 设置displayName
  Mouse.displayName = `WithMouse${getDisplayName(WrappedComponent)}`

  return Mouse
}

//设置组件名
function getDisplayName(WrappedComponent) {
  return WrappedComponent.displayName || WrappedComponent.name || 'Component'
}

// 用来测试高阶组件
const Position = props => (
  <p>
    鼠标当前位置:(x: {props.x}, y: {props.y})
  </p>
)

// 获取增强后的组件:
const MousePosition = withMouse(Position)

class App extends React.Component {
  render() {
    return (
      <div>
        <MousePosition />
      </div>
    )
  }
}

image.png

传递props

image.png