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 ( <div> <h2> render Props的简单使用</h2> { /* 接受子组件向上抛出来的数据*/} <MoveCom render={sonGiveData => { return ( <p>当前鼠标的坐标横坐标: {sonGiveData.x } 纵坐标: {sonGiveData.y }</p> ) }}></MoveCom> </div> ) } } ReactDOM.render( <Father></Father>, document.getElementById('root') )
总结
1. 如何将子组件中的数据抛出去 render() { return this.props.render(数据) } 父组件接受数据 <MoveCom render={sonGiveData => { return ( <!-- 渲染的html以及数据 --> <p>当前鼠标的坐标横坐标: {sonGiveData } </p> ) }}></MoveCom> 我们发现上面这个组件只实现了状态。 并没有实现UI结构的渲染。 UI结构的渲染是交给render函数来决定返回的内容。 小技巧:在React中 left,right,top,bottom是不需要加上px的。 <p style={{ position:'absolute', left:100, top:200 }}> 不需要加上px的 </p> 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接受数据: <MoveCom render={sonGiveData => { return ( <p>当前鼠标的坐标横坐标: {sonGiveData } </p> ) }}></MoveCom> 2.children接收数据: <MoveCom> { (data) => { return ( <p style={{ position:'absolute', left:data.x, top:data.y }}> 横坐标: {data.x } 纵坐标: {data.y } </p> ) } } </MoveCom> 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 ( <div> <h2> render Props的简单使用</h2> <MoveCom> { (data) => { return ( <p style={{ position:'absolute', left:data.x, top:data.y }}> 横坐标: {data.x } 纵坐标: {data.y } </p> ) } } </MoveCom> </div> ) } } ReactDOM.render( <Father></Father>, 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