React中render Props模式


React组件复用

React组件复用的方式有两种:
1.render Props模式
2.高阶组件HOC
上面说的这两种方式并不是新的APi。
而是利用Raect自身的编码特点,演化而来的固定编码写法。

什么是render Props模式

1.把prop是一个函数并且要告诉组件要渲染什么内容的技术,叫做render Props模式。
2.注意的是:并不是该模式叫做render Props就必须使用名为render的props,
实际上可以使用任意的props。
对上面者一句话的详细说明:
子组件向父组件抛出数据的时候使用的是:
this.props.render(数据)中render可以是其他名,如果GiveFather.

render Props的简单使用

现在我们有一个有的需求。
光标放在屏幕上,时时获取当前坐标的位置。
请封装为一个组件。

MoveCom.js 时时获取当前坐标的位置

import React from 'react';
class MoveCom extends React.Component{
  // 提供位置数据
  state = {
    x: 0,
    y:0,
  }
  // 获取鼠标的当前坐标
  moveHandler = e => { 
    this.setState({
        x: e.clientX,
        y:e.clientY
    })
  }
  // 监听鼠标的行为
  componentDidMount() { 
    // DOM已经渲染完成了;可以进行DOM操作
    window.addEventListener('mousemove',this.moveHandler)
  }
  render() { 
    // 将组件中的数据暴露出去this.props.render(数据)
    return this.props.render(this.state)
  }
}
export default MoveCom

父组件展示位置

import React from 'react';
import ReactDOM from 'react-dom'; 
import ClassCom from "./components/ClassCom"
import MoveCom from './components/MoveCom'
class Father extends React.Component{
  render() { 
    return (
      

render Props的简单使用

{ /* 接受子组件向上抛出来的数据*/} { return (

当前鼠标的坐标横坐标: {sonGiveData.x } 纵坐标: {sonGiveData.y }

) }}>
) } } ReactDOM.render( , document.getElementById('root') )

总结

1. 如何将子组件中的数据抛出去
render() { 
    return this.props.render(数据) 
}

父组件接受数据
 {
  return (
    
    

当前鼠标的坐标横坐标: {sonGiveData }

) }}>
我们发现上面这个组件只实现了状态。 并没有实现UI结构的渲染。 UI结构的渲染是交给render函数来决定返回的内容。 小技巧:在React中 left,right,top,bottom是不需要加上px的。

不需要加上px的

this.props.render(数据) 可以将数据传递出去 再次说明:上面这个render这个不一定非要叫做render。 只是这样写render了,你页可以叫做Aa,接受的时候使用也用Aa接收。 其实推荐children去代替render。因为这样更加语义化一些的。 在实际写的过程中也是用children。 下面我们来将代码更改一下,children去代替render。

children去代替render语法上的变化

1.使用render子组件向上抛出数据:
this.props.render(数据) 

1.使用children子组件向上抛出数据:
this.props.children(数据)
在向上抛出数据的时候,只是render变为了children。

2.render接受数据:
 {
    return (
        

当前鼠标的坐标横坐标: {sonGiveData }

) }}>
2.children接收数据: { (data) => { return (

横坐标: {data.x } 纵坐标: {data.y }

) } }
render接收数据的时候,数据是写在组件上 children接收的时候,将数据写在了里面。

render Props中使用 children去代替render

子组件
import React from 'react';
class MoveCom extends React.Component{
  // 提供位置数据
  state = {
    x: 0,
    y:0,
  }
  // 获取鼠标的当前坐标
  moveHandler = e => { 
    this.setState({
      x: e.clientX,
      y:e.clientY
    })
  }
  // 监听鼠标的行为
  componentDidMount() { 
    // DOM已经渲染完成了;可以进行DOM操作
    window.addEventListener('mousemove',this.moveHandler)
  }
  render() { 
    // 将子组件中的数据暴露出去,render变为了children
    return this.props.children(this.state)
  }
}
export default MoveCom

父组件
import React from 'react';
import ReactDOM from 'react-dom'; 
import ClassCom from "./components/ClassCom"
import MoveCom from './components/MoveCom'
class Father extends React.Component{
  render() { 
    return (
      

render Props的简单使用

{ (data) => { return (

横坐标: {data.x } 纵坐标: {data.y }

) } }
) } } ReactDOM.render( , document.getElementById('root') )

优化React中render Props模式

1.推荐给render Props添加一个校验。
因为render Props接收的是一个函数并且是必须写的。
// 规则校验
MoveCom.propTypes = {
  // 如果是使用的children
  children: PropTypes.func.isRequired
  // render: PropTypes.func.isRequired 如果使用使用的render
}

2.移出事件绑定
 // 组件即将卸载的时候,移出事件监听
componentWillUnmount() { 
  window.removeEventListener('mousemove',this.moveHandler)
}

3.这里为什么要移出事件绑定
而我们在页面中用onClick绑定的事件不需要被移除呢?
因为onClick是借用react来完成的事件绑定,react会自动帮我们移除。
这里我们不是借用React来完成的事件绑定,因此我们应该手动移除

子组件优化后的代码


import React from 'react';
import PropTypes from 'prop-types'
class MoveCom extends React.Component{
  // 提供位置数据
  state = {
    x: 0,
    y:0,
  }
  // 获取鼠标的当前坐标
  moveHandler = e => { 
    this.setState({
      x: e.clientX,
      y:e.clientY
    })
  }
  // 监听鼠标的行为
  componentDidMount() { 
    // DOM已经渲染完成了;可以进行DOM操作
    window.addEventListener('mousemove',this.moveHandler)
  }

  // 组件即将卸载的时候,移出事件监听-优化的地方
  componentWillUnmount() { 
    window.removeEventListener('mousemove',this.moveHandler)
  }
  render() { 
    // 将子组件中的数据暴露出去,render变为了children
    return this.props.children(this.state)
  }
}

// 规则校验-优化的地方
MoveCom.propTypes = {
  // 如果是使用的children
  children: PropTypes.func.isRequired
  //  render: PropTypes.func.isRequired 如果使用使用的render
}

export default MoveCom