单向数据流与组件间通信
上文我们已经讲述过, react 单向数据流的原理和简单模拟实现. 结合上文中的代码, 我们来进行这节面试题的讲解: react 中的组件间通信.
那么, 首先我们把看上文中的原生 JS 代码:
- function child(props){
- this.props = props;
- }
- function parent(props){
- this.props = props
- this.state = '这是父函数的一个状态'
- this.childNodes = new child(this.state);
- }
- console.log(new parent('这是一个属性'));
ok, 经过运行, 我们发现打印结果的结构 和 react 父子组件的关系结构是极为类似的, 子函数通过 props 形参接受到父函数的 state.
这个好理解吧? 那么在说 react 组件通信之前, 我们基于原生继续模拟父子组件间的通信.
如上文代码所示, 我们已经实现了父函数通过 props 这个形参向子函数传递数据 -- 是的, 相对而言, 在 react 中, 父组件通过 props(规定了只能通过 props 传递及获取)向子组件进行数据传递. 换句话讲, props 这个实例属性, 表面唯一的作用就是参数传值...
那么, 我们接来下要思考一个问题, 如何在上述代码中实现 子函数向父函数传递数据?
如果我们把函数玩的够熟练, 那么很容易会思考到以下实现方式:
- function child(props){
- this.data = '我是子函数中的 data'
- props.getChildData(this.data);
- this.props = props;
- }
- function parent(props){
- this.props = props;
- this.dataFromChild = null;
- this.getChildData = (data)=>{
- console.log('这个函数被运行了, 我们拿到了传过来的参数:'+data);
- this.dataFromChild = data;
- }
- this.childNodes = new child({
- getChildData:this.getChildData
- });
- }
- console.log(new parent('这是一个属性'));
- (别偷懒! f12, 复制上述代码到控制台运行!)
好的, 简单说下上述代码做出的更改:
1 父函数中定义了一个函数, 通过参数对象 (实则就是 props 啊) 传递给了子函数;
2 这个函数一旦被执行, 会把参数 data 赋值给父函数中的实例属性 data;
3 子函数通过 props 接收到了这个函数, 运行了它, 并且把自己的 data 作为参数传递了进去;
ok, 那么我们经过运行, 发现控制台打印的内容:
哦!!! 于是我们明白了, 我们写原生 JS 的时候, 就是通过:
在父函数中定义方法, 通过参数传递给子函数, 子函数调用这个方法并且把自己数据作为参数, 那么父函数就可以通过形参拿到了~
什么? 有点绕? 那么说的再简单点:
父函数的方法传递给子函数, 被子函数传参调用.
那么赶紧用内存不足的大脑思考思考 react 中是不是也可以啊?
- class Child extends React.Component{
- data = '我是子组件中的 data'
- render(){
- this.props.getChildData(this.data);
return <div > 我是 Child 组件</div>
- }
- }
- class Parent extends React.Component{
- childData=null
- getChildData = (data)=>{
- this.childData = data;
- console.log(data);
- }
- render(){
- return <Child getChildData = { this.getChildData } />
- }
- }
- console.log(<Parent />)
上面的代码够简练了吧(比中指)!
那么我们运行上述代码发现 -- 乖乖, 真的拿到了~~ 这不还是一样吗? 我们玩的不是 react 吗? 怎么成原生 JS 了啊? 啥啊谁啊我在哪啊??
实则所有单向数据流的 JS 框架都可以通过上述的方式进行子组件向父组件的通信.
非常好, 现在我们来整理一下 react 的父子组件间通信规则:
* 父传子: 父组件通过 props 传参呗......*
* 子传父 : 父组件通过 props 传参呗......*
啥? 我写重了?
(哼哼一声我露出了鄙视的微笑, 并在下面多写了一行)
*** 子传父完整版: 父组件中定义函数, 通过 props 传递给子组件, 子组件调用这个函数并传参.***
嗯... 经过思考, 我们得出了这样一个结论: 子传父这样的逆向通信, 实际也是符合单向数据流的概念. 无非就是把函数当做参数传递下去而已啊!!!(重点是这句啊~~~react 中的逆向通信的方式和单向数据流完全不冲突啊~)
子传父 (逆向通信) 的其他方式
除开上面讲过的 父组件中定义函数传递给子组件并被其调用 这种 JS 通用方式, 在 react 中我们还可以怎样玩?
在 vue,React 中都有 ref 这样一个特殊的实例属性.
react 中 ref 具备两种作用:
1 标记 dom 的话, 能获取 dom 实例;
2 标记子组件的话, 能获取子组件实例的所有数据(包括子组件的 props,state, 定义的方法, 实例...).
那么也就是说, 父组件通过 this.ref 就拿到子组件的任何数据了... 就这么简单啊.
当然, 依照 react 的尿性, 文档中特意提到了一点: 不要轻易用这玩意啊, 危险啊, 别冲动啊小伙子们~
事实上, 经过 react 的版本变化, ref 赋值目前有三种方式 : 字符串, 回调, CreateRef() // 这个是 16.3 后的新增 API
迭代维护做的都很到位啊~ 凭啥只用在表单控件里啊~
当然, 关于 ref 的花式玩法我们会在本系列后面内容讲到.
远亲组件的通信
其实无论做 react 还是 vue 或者其他项目, 我们必须要明确, 写的还是 JS.(这也是为什么我一直把原生和 react 放在一起讲)
那么远亲组件的通信, 我们即时对 react 毫无了解, 也能至少说出一万种方式...
例如:
1 通过缓存 : 组件 A 把数据存到缓存中, 组件 B 就可以从中取出;
2 通过 url : 通过 location 对象拿到...;
3 通过与后端配合: 组件 A 把数据扔到接口里去, 组件 B 可以从中拿到...;
以上方式, 我称之为通过第三方媒介的形式.
(插一句: 有木有觉得 redux 中 store 共享跟 session 级别缓存很类似?)
也就是说, 远亲组件的通信, 我们抛开 react 去思考得出一个结论:
-- 通过第三方媒介作为一个存储地点, 实现数据共享.
ok 我们把话题转回来. react 中, 同系远亲的话(太太爷爷到重重孙子), 完全可以通过 context 嘛(上一篇有讲, 后面也会出 context 的专章)...
至于不是很远的关系, 利用 props 一层一层往内传啊. (例如爷爷传到孙子)
逆向: 子调用爷爷的函数并传参就实现了子传爷爷;
同级 : 子 1 传父, 父传子 2 ;
很远关系: 1 context(自己实现试试啊~) 2 通过第三方媒介共享( 缓存, url, 服务端, 以及后面我们会讲到的 redux,react-redux,dva 等全局状态存储管理插件);
我们发现, 就单单 react 的话, 传来传去还是 父传子 子传父啊...... 最多特殊情况用到 context(无论多远的关系, 最终肯定有个统一的祖宗啊 < App ==!/>)而已啊~
总结
这章讲述了 react 的基础必面的面试题:
如何在 react 项目中实现组件间的通信.
也可能会引发一些 react 与项目与原生的思考(这是我想要的).
如果本章内容对您有帮助, 请点个推荐哦~
来源: https://www.cnblogs.com/sanchang/p/10516067.html