react组件之间传值
看过一些文章介绍react组件之间传值,无外乎以下几种情况:父子组件之间相互传值,兄弟节点之间传值。最常见的就是父子组件,做法也很简单:就是在父组件中直接通过props属性的方式将函数或者值传给子组件。父组件有变化,相应的值就会体现在子组件中;子组件有动作发生,则调用函数,函数是父组件传递过来的,父组件就能获取子组件的值。
还有一种情况,就是兄弟节点之间要传值,这个还比较复杂,因为他们之间没有直接的交集,但是他们有一个共同的父组件,可以借助父组件传递值,所以还是回到了父子组件传值上。
这里有个需求:有一个菜单列表,点击菜单会选择相应的选项,有一个标签页选项,点击标签可以切换选项。菜单和标签页可以产生一种联动,他们是两个兄弟节点,现在需要考虑的是选择菜单,标签页也跟着动,标签页选择的时候,菜单也跟着响应,这个示例可以很好的演示多种情况传值,效果如下所示:
代码部分:
import React,{useState} from 'react'
import {Tabs,Menu,Divider} from 'antd'
import 'antd/dist/antd.css'
const {TabPane} = Tabs
const MenuList = (props)=>{
const {current,setCurrent} = props;
const handleClick = e =>{
setCurrent(e.key)
}
return <Menu onClick = {handleClick} selectedKeys = {current} >
<Menu.Item key="a">aaa</Menu.Item>
<Menu.Item key="b">bbb</Menu.Item>
<Menu.Item key="c">ccc</Menu.Item>
</Menu>
}
const TabComponents = (props)=>{
const {activeKey,setActiveKey} = props;
const changeTabHandler = (key)=>{
setActiveKey(key)
}
return <Tabs activeKey={activeKey} onTabClick = {changeTabHandler}>
<TabPane tab="aaa" key="a">this is aaa</TabPane>
<TabPane tab="bbb" key="b">this is bbb</TabPane>
<TabPane tab="ccc" key="c">this is ccc</TabPane>
</Tabs>
}
const MyTabs = ()=>{
const [activeKey,setActiveKey] = useState('a')
return <div>
<MenuList setCurrent = {setActiveKey} current={activeKey}/>
<Divider/>
<TabComponents activeKey = {activeKey} setActiveKey = {setActiveKey}/>
</div>
}
export default MyTabs
这里使用了antd中的Menu和Tabs控件形成MenuList和TabComponents,他们组成一个新的组件MyTabs,在父组件中,我们通过useState函数定义了一个变量和设置变量的方法,分别对应activeKey,setActiveKey,最终将他们都传入MenuList和TabComponents中。
这种做法,达到了联动的效果,却破坏了Tabs默认的onTabClick事件,本来Tabs的切换是根据用户点击来做切换标签页,但是现在变成了既可以手动也可以自动,手动就是,用户点击菜单选项,通过外部传入值,切换tab,这里是通过改变默认值activeKey的方式实现,如果我们不添加onTabClick函数响应,那么用户点击标签页会失效。
==========================================================================
还有一种做法,可以通用,不仅可以父子之间,还可以是兄弟节点之间传值,就是发布订阅模式。这种方式,不需要父节点来维护值的状态,因此也不需要通过props属性传值,直接在需要传值的组件之间来通过发布订阅即可。组件内部自己维护状态的改变,而且这种方式也是可以双向的传值。
先上效果图,跟上面没什么两样:
代码需要增加一个简单的发布订阅实现:
EventEmmiter.js
const EventEmmiter = {
_events:{},
dispatch:function(event,data){
if(!this._events[event])
return;
for(var i=0;i<this._events[event].length;i++)
{
this._events[event][i](data);
}
},
subscribe:function(event,callback){
if(!this._events[event])
this._events[event] = []
this._events[event].push(callback)
}
}
export default EventEmmiter
PubSub.js
import React,{useState} from 'react'
import {Menu,Tabs,Divider} from 'antd'
import EventEmmiter from '../utils/EventEmmiter'
import 'antd/dist/antd.css'
const {TabPane} = Tabs
const MenuList = (props)=>{
const [current,setCurrent] = useState('a');
const clickHandler = (e)=>{
EventEmmiter.dispatch('changeTab',e.key)
setCurrent(e.key)
}
EventEmmiter.subscribe('changeMenu',(key)=>{
setCurrent(key)
})
return <Menu onClick = {clickHandler} selectedKeys = {current}>
<Menu.Item key="a">aaa</Menu.Item>
<Menu.Item key="b">bbb</Menu.Item>
<Menu.Item key="c">ccc</Menu.Item>
</Menu>
}
const TabComponent = (props)=>{
const [current,setCurrent] = useState('a');
const clickHandler = (e)=>{
EventEmmiter.dispatch('changeMenu',e)
setCurrent(e)
}
EventEmmiter.subscribe('changeTab',(key)=>{
setCurrent(key)
})
return <Tabs activeKey={current} onTabClick = {clickHandler}>
<TabPane key="a" tab="xxx">xxx this is aaa.</TabPane>
<TabPane key="b" tab="yyy">yyy this is bbb.</TabPane>
<TabPane key="c" tab="zzz">zzz this is ccc.</TabPane>
</Tabs>
}
const PubSub = ()=>{
return <div>
<MenuList/>
<Divider/>
<TabComponent/>
</div>
}
export default PubSub
这种方式比起前面,代码量虽然有增加,但是它却是一种通用的做法,不用考虑组件的关系。发布订阅是分开的,他们各自作用在不同的组件里面,是成对出现的。
本文地址:https://blog.csdn.net/feinifi/article/details/112565060
上一篇: vue中lintOnSave配置
下一篇: 【面试复习】 —— JavaSE