React 函数组件-多层组件值传递父传子
由于本人是React新手,对于Javascript的各种传值、编写逻辑也不是很熟悉,于是在工作中遇到了这样的一个小问题:
在多层组件传值的时候,如何将父组件中的值传递到子组件中?
在此我将自己的心得体会记录下来,也因为函数组件(或者说React Hooks)区别于类组件是React17以后新增加的许多特性,而互联网上目前的使用还是以类组件为主。不过我认为函数组件更加简明,有其优越性,并且公司要求使用函数组件开发(逼着自己学),所以将自己的学习笔记记录公开,也是对函数组件的一些经验贴的小贡献。
现在我们有一个具体的场景:我们需要查询某个房间中某个库位的货物信息,库位是在父组件 HomePage 中,使用 Picker 选择器返回的值。现在我需要把这个值,传递过两层的组件,也就是到达子子组件。
最终在子子组件中,通过 data.filter() 查询的形式,将数据中的 location 字段和父组件中 Picker 选择器返回的值进行比对,查找出正确的值,并且渲染在页面上。
以上的任务,使用 React 函数组件实现。
我们当前的任务是,将 HomePage 产生的 location 值,传递到子组件 TransferModal, 再传递到子子组件 Transfer. 同级的 Check 和 Put 同理。
首先,可以明确的一点是,React 的父传子通信通过 props 实现。React 官网就将这种父组件传到子组件的值称为 “props”:Passing Props to a Component – React
但是,这篇文章的代码没有使用 props,这就显得比较抽象😂 文档中关于 props 的例子,都用了具体的参数名,通过花括号的方式,打包并且进行传递。不是说这种方式不好,但是当我们需要在父组件中多向子组件传一个 props 值的时候,需要在子组件的函数声明处新增加一个,会有些麻烦。
比如,考虑父组件 Profile 与子组件 Avatar:
假设我在父组件的 Profile 中,使用 Avatar 的时候,增加了 props 名为 a,那我如果需要在子组件中使用 a,是否需要在子组件函数的声明中,多加一个 a 呢?
而且这个花括号包裹起来的 props,并没有写一个 props 来的直接易懂。
所以对于 Avatar,我会这么写:
function Avatar(props) {
{person, size, a} = props
return (
<img
className="avatar"
src={getImageUrl(person)}
alt={person.name}
width={size}
height={a}
></img>
)
}
发现了没,function Avatar(props)
中的 props 就是父组件传到子组件的值。那如果我需要从子组件传到子子组件,只需要在子子组件中的函数形参里面,也写一个 props,再在子组件里面传一下参数,就可以了!
具体实现:
HomePage(父组件)中:
其中 ref 是自定义的 React useRef。由于 TransferModal, CheckModal, PutModal 都是基于 React 的模态弹窗 Masking 组件,Masking 组件中,需要控制 setVisible 参数用于控制弹窗的弹出 / 隐藏。我们在父组件、子组件、子子组件中都需要有按钮来控制 Masking 的弹出或者关闭,所以使用 useRef 来控制 ref.current.setVisible 的值为 true 或者 false。将 ref 向下传递也是为了保证整个项目中,弹窗的弹出或者隐藏状态不随组件的改变而改变,只由用户决定。(这里只是提一下为什么 ref 这个 props 存在,可以忽略)
location 的值存储在 singleValue 中,将其赋值给 loc 并且传递给子组件。其中 TransferModal 不需要 location 值(实际项目需要),所以不传值。
CheckModal(子组件以他为例)中:
声明函数的时候,形参加入 props(ref 是因为上面的父组件中,给子组件加了一个 ref 所以分开引用,不需要加花括号)
如何获取 loc 的值?很简单:使用语句 const {loc} = props
即可获取到 loc 的值,并且传递给 Check 组件,写在其 props 部分即可。
function CheckModal(props, ref) => {
const {loc} = props
return <Masking
...props // irrelevant code
>
<Check loc={loc}/>
</Masking>
}
Check(子子组件)中:
const Check = (props) => {
const {loc} = props
let filteredData = []
useEffect(() => {
filteredData = data.filter((item) => item.a === loc)
// irrelevant code
},[loc])
let list = filteredData.map((item) => {
return (
<div key={item.id}>
<div>{item.name}</div>
<div>{item.code}</div>
</div>
)
})
return (
{list}
)
}
声明函数的时候,形参加入 props
使用语句 const {loc} = props
获取 loc 的值,然后使用 useEffect 钩子,监听 loc 值的变化来根据不同的 loc 获取不同的物品信息(很正常,因为我们会按照需求获取不同库位的物品信息),再将获取的数据通过 map 方法渲染出来,最后返回。结束!
这样我们就实现了把父组件的值传到子组件再传到子子组件,附加功能有在子子组件中使用 useEffect 监听数据的动态变化并进行筛选,并 map 最终渲染。
希望我作为一个React新手,将自己学习的心路历程一步步阐释会让人觉得清楚,流程清晰。也希望大佬们对我文章中表述不规范的地方进行指正,感谢阅读!