react 这种组件化设计框架,怎么能拿到子组件的值呢?

247 天前
 hahaFck

最近在学 react,遇到一个问题请教一下,假如组件都是用 function 定义的,如果页面的结构是这样的:

我想在 toolbar 中的一个 button 点击事件中获取 Grid 控件的值,该用什么方法实现呢。 按照以往非组件化的思路应该是直接获取到这个 grid 对象,在调用对应的 getValue 方法就可以了。

虽然组件支持传递回调函数,在 grid 内部,state 变化时调用回调函数,但是这样的话回调函数就要在 page 里面从 layout 传到 grid ,感觉这种思路太不符合直觉了,因为 layout 和 some 组件根本就不应改有 callback 的 prop ,如果 some 下面有 5 个组件,那就要传递 5 个 callback ,太可怕了吧,并且多加一个组件就要去修改 some 的代码也是不对的。

后段 coder 最近在学前端,没用 react 做过项目,不知道遇到这种情况改怎么解决,有什么好的方法或者 lib 能够优雅的解决这个问题么。

4877 次点击
所在节点    React
60 条回复
Histo
247 天前
可以把 Grid 的 state 提升到 Page 中,或者直接在 Page 上包裹一个 Context.Provider ,用 context 管理状态
leaflxh
247 天前
另一种自用的办法是在 Toolbar 这个组件里的 useEffect([])里,挂一个事件监听:
//定义通信格式
interface IToolbarDataChangeEvent{
msg:string
}
//处理函数
const handleDatachange = (detail: IToolbarDataChangeEvent) = > {console.log(detail.msg)}
//注册事件
document.addEventListener("toolar::handleDataChange", handleDataChange)
//本组件卸载时的清除
return () => {document.removeEventListener("toolar::handleDataChange", handleDataChange)}

然后 Grid 更新数据的时候发一个事件过去:
const event = new CustomEvent<IToolbarDataChangeEvent>("toolar::handleDataChange", {detail: {msg: "a msg from grid"}});
document.dispatchEvent(event)
leaflxh
247 天前
来自野路子前端,不确定是否是推荐的做法(
zbinlin
247 天前
这种情况一般用 Context
Xu3Xan89YsA7oP64
247 天前
要学会用 gpt
我的话会直接用状态管理库
Provide 给 Grid 控件去赋值,属于狗屎代码
kneo
247 天前
能处理的方法很多。比如把多个 callback 封装成一个,使用 children 传递子控件,使用 context/provider 。但是我想说,才 5 个 callback 有什么可怕的?搞后端没这么脆弱。
lqm
247 天前
直接上状态库,zustand ,早晚会上的
huijiewei
247 天前
用 context 跨级别传
hahaFck
247 天前
@Histo
@zbinlin
如果用 context 的话,useContext 的代码就要硬编码到 grid 组件中,这样这个组件也不通用了吧,放到另外页面的 context 里面又要重新写一份。
wisetc
247 天前
这是 react 特别的地方,你说的对 react 组件是基于一般属性和回调属性的单向数据流,所有的子组件都可以由父组件自上而下赋值参数来控制,组件间也是提倡组合大于继承,不同的组件间传参共享数据是通过公共父类组件居中调度,这一点在某些清新下确实会不太方便,但是也在一定程度上避免了组件间的相互修改,而是给它什么就是什么显得很确定。若是例子中的情形也是可以通过设定属性的,react 是可以透传属性的,跨组件传递数据流确实会有一些不太方便就是,大应用可以用集中的数据管理作为公共的数据源获得其中的状态,然后转化为普通组件的属性
orzorzorzorz
247 天前
是的,照文档看且不考虑状态管理,你只能一层层往上传。context 自己用还行,人多了就很乱。
歪个楼。19 年那会我自己要开个项目,rva 选了半天,最后选了 a 。从结果看,只能说 angular 这种填空式开发是真的是在三年后等你,不太会有像 op 主楼里这样的心智负担。
Ghrhrrv146
247 天前
使用状态管理库最简单
wu67
247 天前
使用状态库,
虽然项目早期时可能你会觉得烦琐,但是越往后越多需要共享状态的业务
ChefIsAwesome
247 天前
这就是典型的组件一对多的模式,要靠一个中间人来完成传递。这个中间人肯定是这几个组件的上一级。前面几层楼推荐的 context ,状态管理库,都是这么个中间人。你定义 customEvent ,在 windows 上 dispatch ,那也叫中间人,也能解决你的问题。
你随便写就好了,不要想着非得符合“react”的路子才行。
ztcaoll222
247 天前
context 、状态库、或者 Grid 直接写 localStorage(笑
Leviathann
247 天前
@hahaFck 这是 explicity 的体现,不然你怎么知道这个组件有一个可以被捕获的事件

组件和一个 context 的配合一起使用也是一个比较常见的 pattern
darkengine
247 天前
状态上移,我会把所有数据和点击的响应函数都放在 Page 里,Toolbar 只负责通知 Page 某个 Button 被点击了,Layout, Some, Grid 只负责根据数据展示。
maolon
247 天前
状态上移+1 同时使用 children 的方法摊平组件
<Page>
<Toolbar/>
<Layout>
<some>
<Grid {...props}>
</some>
<Laout>
</Page>
ymcz852
247 天前
@orzorzorzorz 那么,请问 angular 是如何处理呢🤔
ebushicao
247 天前
最简单的方法就是把状态提升到需要的最上层,不过这样在组件层次过多的情况下既不利于维护,也会存在性能问题,尤其是中间传递某些组件不需要用到这个状态。
然后就是用 Context API ,因为不推荐所以详情建议去看 React 官方文档。
然后是使用状态管理库,把这种多个组件使用的状态交由状态管理库管理,算是最合适的处理了,喜欢稳定的就是 redux 和 mobx ,喜欢更现代的就看看 recoil ,zustand ,jotai

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1032409

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX