React实现父组件调用子组件的两种写法
作者:双子座434
前言
react通信分很多种,比如:父子通信,兄弟通信等等。这里我们就简单说一下父子通信,父子通信分为:父组件调用子组件里面的方法;子组件调用子组件里面的方法。子调父一个porps就可以解决了,这里我们着重说一下父组件调用子组件。废话不多说,直接上代码:
函数式写法:
方法一:
child.js
import React, { useImperativeHandle, forwardRef } from "react"; function Child(props, ref) { useImperativeHandle(ref, () => { return { onClick: handleClick, } }); const handleClick = () => { alert('点击了'); } return ( <button>我是按钮</button> ) } export default forwardRef(Child);
index.js
import React, { useRef } from "react"; import Child from './child'; function Calling() { const nRef = useRef(); const handleClick = () => { nRef.current.onClick(); } return ( <div> <button onClick={handleClick}>点击后调用子组件</button> <Child ref={nRef} /> </div> ) } export default Calling;
父调子通过ref,简单来说:使用钩子函数将子组件自定义的方法绑定到ref.current上面。这里用到了三个钩子:useRef、useImperativeHandle, forwardRef。
1.useRef:父组件使用useRef通过参数(这里的参数命名必须为ref)传递给子组件
2.useImperativeHandle:将子组件自定义的函数添加到父组件的ref上,注意这里,第一个参数为ref,第二个参数为对象(也就是父组件中调用的方法或者要取得属性或者值)。
3.forwardRef:将引用的ref传递给子组件,这时子组件接收到的第一个参数是porps,第二个参数是ref。
上面因为传递给子组件的参数为ref关键字,所以子组件里必须要有接收的方法。
方法二:
child.js
import React from "react"; function Child(props) { const handleClick = () => { alert('点击了'); } props.nref = { onClick: handleClick, } return ( <button>我是按钮</button> ) } export default Child;
index.js
import React from "react"; import Child from './child'; function Calling() { const nRef = {}; const handleClick = () => { nRef.onClick(); } return ( <div> <button onClick={handleClick}>点击后调用子组件</button> <Child nref={nRef} /> </div> ) } export default Calling;
index.js(解法二)
import React, { useRef } from "react"; import Child from './child'; function Calling() { const nRef = useRef(); const handleClick = () => { nRef.onClick(); } return ( <div> <button onClick={handleClick}>点击后调用子组件</button> <Child nref={nRef} /> </div> ) } export default Calling;
大家这里注意看方法二的两个index.js文件差异性,无非就是将空对象换成了useRef,为什么要这样写呢,这样写有什么优点吗?当代码量一样的时候,大家就应该思考一件事情:性能。当然,哪个性能好就选择哪个,我对方法二的这两个index文件做了一下对比(实际上就是空对象和useRef的比较),空对象就不用解释过多了:引用类型...;我们着重解释一下useRef:可以帮我们缓存数据,返回一个ref对象,里面的ref.current是用来存储数据的,返回的ref对象不会被重新创建(言外之意就是他爸爸无论渲染多少次,这个对象指向地址永远只有最原始的那个),这里值的变化不会引起组件的重新render,组件不会因为状态的更新而更新(也就是说,组件状态改变了,这里可以保存改变的状态),如果只想要保存状态,不影响视图更新,并且可以同步获取和更新状态的话,建议使用useRef。
大家想一想,如果他爷爷不断渲染,使用 const nRef = {};是不是就会不断的给nRef赋新的地址,之前的地址只有经过一段时间的不使用才会被垃圾回收机制(不懂垃圾回收机制的去翻翻哈)释放掉;而useRef无论他爷爷渲染多少遍,它的地址最终只有一个。
类组件写法:
方法一:
child.js
import React , { Component } from "react" class Child extends Component { handleClick = () => { alert('点击了'); } render(){ return (<div>子组件</div>); } }
index.js
class Parent extends Component { constructor(props) { super(props); this.Child = React.createRef(); } handleOnClick = ()=>{ this.Child.current.handleClick(); } render(){ return (<div> <button onClick={this.handleOnClick}>click</button> <Child ref={this.Child}></Child> </div>); } }
方法二:
child.js
import React , { Component } from "react" class Child extends Component { componentDidMount(){ this.props.onRef && this.props.onRef(this); } handleClick = () => { alert('点击了'); } render(){ return (<div>子组件</div>); } }
index.js
class Parent extends Component { handleOnClick = ()=>{ this.Child.current.handleClick(); } render(){ return (<div> <button onClick={this.handleOnClick}>click</button> <Child onRef={ data => this.Child = data }></Child> </div>); } }
对比一下类组件的两个方法:
方法一:简单易懂,缺点就是:如果子组件中嵌套了高阶组件,那么就无法指向真实的子组件
方法二:写法更简单易懂,粗暴,缺点就是:需要自定义props属性
这里其实还有一个方法三,思路:大家可以利用高阶组件+反向继承实现。
到此这篇关于React实现父组件调用子组件的两种写法的文章就介绍到这了,更多相关React父调子内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!