从 Vue 的视角学 React(四)—— 组件传参
组件化开发的时候,参数传递是非常关键的环节
哪些参数放在组件内部管理,哪些参数由父组件传入,哪些状态需要反馈给父组件,都需要在设计组件的时候想清楚
但实现这些交互的基础,是明白组件之间参数传递的方式,和各自的优缺点
一、父组件传参到子组件
和 Vue 一样,React 中从父组件到子组件的传参也是通过 props
不过在 Vue 项目中,需要在先组件里定义将要接收的 props,而 React 可以直接获取
而且 props 不光可以接收 Number、String 等基本类型,还可以接收 Function,这点在《从 Vue 的视角学 React(三)—— 事件处理》中也有提到
另外 props 还可以直接接收组件,类似于 Vue 中的 slot,后面会详细介绍
二、子组件向父组件传参
在项目中,也会有需要更新 props 的时候
但和 Vue 一样,React 中的 props 也是单向的,一定不能在组件内部直接修改 props 的值
而应该采用事件上报的方式,让父组件修改相应的状态
整个过程就像是 Vue 中的 $emit,只是将 $emit 中声明的自定义事件放到了 props 中
上面的 updateText 就是一个自定义事件,父组件为这个自定义事件添加了处理函数 handleUpdateText
如果子组件需要向父组件传递参数,可以在触发自定义事件 updateText 的时候,向事件处理函数传参
然后父组件在对应的事件处理函数 handleUpdateText 中获取到子组件传过来的参数
三、状态提升
除了父子之间的传参,还会有两个平级组件之间的参数传递
React 的推荐方案是,将两个子组件的参数都放到父组件中处理,这就是状态提升
假设有 boy 和 girl 两个组件,它们都是组件 father 的子组件
组件 girl 中有一个 food 状态,组件 boy 中有一个 age 状态,food 会随着 age 的变化而变化
如果 age 和 food 都是对应组件的 state,维护起来就比较麻烦
而如果将 age 和 food 都作为 props 传入,就可以在父组件 father 中维护这两个状态
当需要更新 age 的时候,从 boy 组件上报事件,然后在父组件中同时更新 food 和 age
React 是单向数据流,在设计组件的时候,应当始终保持自上而下的数据传递,而不是尝试在不同组件间同步 state
如果某些数据可以由 props 或 state 推导得出,那么它就不应该存在于 state 中
虽然这种方式会比双向绑定需要编写更多的代码,但更利于维护
四、限制 props 类型
良好的组件不可避免的会用到很多 props,为这些 props 添加类型校验就尤为重要
Vue 本身就有一套很完善的 props 类型校验配置,React 之前也有 React.PropTypes
但支持 TypeScript 之后,就将这部分功能拆成了独立的第三方库 prop-types
npm install prop-types -S
引入 PropTypes 之后,在组件内定义一个静态属性 propTypes(注意大小写),然后定义具体的规则
参考上图的示例,校验规则由 . 语法连接,如果有多个类型,就使用 oneOfType
更多关于 PropTypes 的使用可以查看官方文档
除了类型校验,有时候还需要给 props 添加默认值,这时候可以用 defaultProps
五、组件嵌套
虽然开发组件的时候,我们总是希望能尽量满足需求,以减少后期的工作量
但一万个读者就有一万个哈姆雷特,一个组件不可能满足所有用户的需求,所以有时候就需要为组件提供一些扩展性
另外,还有一些组件本身就是作为容器开发的,这些场景都需要将组件作为 props 传给子组件
const Child = props => <div>{props.content}</div> const Tag = props => <div>This is tag</div> const Parents = props => <Child content={<Tag />}/>
上面的代码中,子组件 Child 会接收一个 props 属性 content
然后在父组件 Parents 中,将 Tag 组件作为 content 的值传给了子组件 Child
不过这样的写法并不优雅,如果能像 Vue 的 slot 那样,直接将子组件嵌套在父组件的标签内,就更符合 HTML 标签的结构
这时候就可以用到 props.children
const Child = props => <div>{props.children}</div> const Tag = props => <div>This is tag</div> const Parents = props => <Child><Tag /></Child>
从上面的代码可以看出,组件标签之间嵌套的内容,可以在组件内通过 props.children 接收到
事实上,props.children 是一个数组,如果不加具体的元素下标,就会将所有的元素渲染出来
如果标签内有多个节点,porps.children 就会将自身组件作为根节点,以数组的形式将组件内的 DOM 结构虚拟出来
而且 props.children 不单可以接收组件,还可以接收字符串
六、Context
在维护大型项目的时候,仅靠 props 和事件来传参是不够的,所以 Vue 提供了 Vuex 来维护状态
React 也有状态管理工具,常用的有 Redux、Mobx,如何使用这些工具我会在以后的文章中介绍
但在使用这些工具之前,需要了解 context,因为 Redux 和 Mobx 都是基于 context 实现的
如果组件的层级很深,仅使用 props 层层嵌套传参的话就非常的冗余
这时如果有一个全局变量,在顶层组件定义之后,直接在底层组件中获取,就会非常简洁,context 就是这样的全局变量
// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。
// 为当前的 theme 创建一个 context(“light”为默认值)。
const ThemeContext = React.createContext('light'); class App extends React.Component {
render() {
// 使用一个 Provider 来将当前的 theme 传递给以下的组件树。
// 无论多深,任何组件都能读取这个值。
// 在这个例子中,我们将 “dark” 作为当前的值传递下去。
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
} // 中间的组件再也不必指明往下传递 theme 了。
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
} class ThemedButton extends React.Component {
// 指定 contextType 读取当前的 theme context。
// React 会往上找到最近的 theme Provider,然后使用它的值。
// 在这个例子中,当前的 theme 值为 “dark”。
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
但 context 的使用会极大的增强组件之间的耦合性,项目中并不建议直接使用
所以我直接复制粘贴了官方文档的代码,仅为了解 context 这个概念
小型项目中,如果有深层次的传参,应当从组件设计上解决问题,比如直接将组件传下去
而大型项目中,如果需要用到 context,更推荐使用 redux 和 mobx 这些成熟的状态管理工具
参考资料:
从 Vue 的视角学 React(四)—— 组件传参的更多相关文章
- React(7) --react父子组件传参
react父子组件传参 父级向子级传参:在父组件中,我们引入子组件,通过给子组件添加属性,来起到传参的作用,子组件可以通过props获取父组件传过来的参数. 在父组件中: import React f ...
- 从 Vue 的视角学 React(三)—— 事件处理
如果要处理某个元素的 click 事件,原生 js 可以直接为该元素添加一个 onclick 函数 Vue 封装了 v-on 指令,可以简化为 @click 并添加相应的函数 React 的开发思想是 ...
- 从 Vue 的视角学 React(二)—— 基本语法
基于 Vue.js 开发的时候,每个 vue 文件都是一个单独的组件,可以包含 HTML,JS,CSS 而 React 是以函数为基础,每个 function 就是一个组件.虽然 JSX 让 HTML ...
- 从 Vue 的视角学 React(一)—— 项目搭建
虽然 Vue 在国内一家独大,但在全球范围内,React 依然是最流行的前端框架 最近和一些朋友聊天,发现很多项目都选择了 React 技术栈,而且公司的新项目也决定使用 React 我一直以来都是走 ...
- vue组件传参
一.父子组件的定义 负值组件的定义有两种,我称为常规父子组件和特殊父子组件. 1.1.常规父子组件 将其他组件以import引入用自定义标签接收,在当前组件中component里注册该标签,页面上可以 ...
- vue中的路由传参及跨组件传参
路由跳转 this.$router.push('/course'); this.$router.push({name: course}); this.$router.go(-1); this.$r ...
- vue 组件传参及跨域传参
可以完成跨组件传参的四种方式 // 1) localStorage:永久存储数据 // 2) sessionStorage:临时存储数据(刷新页面数据不重置,关闭再重新开启标签页数据重置) // 3) ...
- Vue 子组件向父组件传参
直接上代码 <body> <div id="counter-event-example"> <p>{{ total }}</p> & ...
- vue 父子组件传参
父向子组件传参 例子:App.vue为父,引入componetA组件之后,则可以在template中使用标签(注意驼峰写法要改成componet-a写法,因为html对大小写不敏感,component ...
随机推荐
- Angle Beats Gym - 102361A(计算几何)
Angle Beats \[ Time Limit: 4000 ms \quad Memory Limit: 1048576 kB \] 题意 给出 \(n\) 个初始点以及 \(q\) 次询问,每次 ...
- docker nginx 命令。
docker run -d -p 80:80 -p 443:443 --name baiqian.site --restart=always -v ~/wwwroot/layx:/usr/share/ ...
- 记录Windows下文件操作记录
https://blog.csdn.net/huashuolin001/article/details/73863324
- vs连接oracle
参考: https://www.cnblogs.com/gguozhenqian/p/4262813.html
- YYCache 的整体架构类图

- jQuery必知必会
原文地址:https://my.oschina.net/u/218421/blog/37391 jQuery优势 轻量级 强大的选择器 出色的DOM操作的封装 可靠的事件处理机制 完 ...
- kali渗透
局域网-断网&劫持(kali) 1.查看局域网中的主机 fping –asg 192.168.1.0/24 2.断网 arpspoof -i wlan0 -t 192.168.100 19 ...
- [记录]mscorlib recursive resource lookup bug解决方法
[Content]Expression: [mscorlib recursive resource lookup bug]Description: Infinite recursion during ...
- [转帖]国产统一操作系统UOS龙芯版正式上线
国产统一操作系统UOS龙芯版正式上线 2019/12/13 12:49:31来源:IT之家作者:骑士责编:骑士评论:446 https://www.ithome.com/0/462/725.htm ...
- Sitecore客户体验成熟度模型之旅
“成熟”这个词带来了很多想法:你在青年时不愿意找到工作?你四岁的孩子偶尔发脾气?可能还有你的公司能否在数字化时代提供个性化的客户体验? 你如何定义CX成熟度?如果您的CX战略仍处于开发阶段,您需要达到 ...