React 组件间的数据流动

1、一般而言

在简单的应用场景下,有下面两种方式实现组件间的通信

  • 通过 props 传递

    直接向子组件添加 props 属性即可,这种方式简单便捷,但只适用于父组件向直接子组件传递数据,遇到组件层级较深或者同级组件有通信需求的场景时就显得比较麻烦;

    由于 React 讲究单向数据流,子组件无法向父组件直接传递数据,通常的方法还是通过 props 属性向子组件传递回调方法,子组件调用回调方法时可传入相应参数以实现通知父组件的目的。

  • 订阅-发布 模式

    在涉及到组件层级较深或者同级组件有通信需求的场景时,订阅-发布模式可以说是较为直接的解决方案

    class MyEventEmitter{
        constructor(){
          	// 初始化事件容器
            this.eventMap={}
        }
      	// 订阅事件
        on(type,listener){
            if(typeof listener!=='function'){
                throw new Error('the type of listener should be function');
            }
            if(!this.eventMap[type]){
                this.eventMap[type] = [];
            }
            this.eventMap[type].push(listener);
        }
        // 取消订阅事件
        off(type,listener){
            if(this.eventMap[type]){
                this.eventMap[type].splice(this.eventMap[type].indexOf(listener)>>>0,1);
            }
        }
      	// 触发事件
        emit(type,params){
            if(this.eventMap[type]){
                this.eventMap[type].forEach(listener => {
                    listener(params);
                });
            }
        }
    }
    
    module.exports = new MyEventEmitter();
    
2、React 官方提供的 Context

组件间通信这么重要的问题就只是上面那些 “野路子” 方案么?当然不是。

他们提供了类似于生产者/消费者模式的 Context 功能来实现跨组件通信,在 React 16.3 版本以前,如果要使用这个功能需要这样:

在提供数据的组件中定义一个 getChildContext 方法,把要提供的数据当做返回值,另外再添加一个 childContextTypes 属性,把要提供的数据项名称和名称对应的数据类型以对象形式安排上;

而对于数据的消费者呢,则需要添加 contextTypes 属性,再次把要使用的数据项名称和名称对应的数据类型以对象形式安排上,然后才可以在消费者组件内部通过 this.context. 的方式得到生产者提供的数据。

是不是听上去就不想用了?

另外此时的 Context 还有个很大的弊端,首先数据在组件间传递过程中需要保证一致性,然而,在层层的组件树中,但凡有一个组件的 shouldComponentUpdate 的返回值是 false ,那么在它的后代组件获取的 context 数据就不能得到及时的同步。

连 React 官方都怯生生说:这是一个实验性的 API ,不太推荐大家使用。

直到 React 16.3 版本对这个 API 更新后消除了上面所说的弊端,Context 才算得上是一个可以一用的 API.

更新之后的使用方法一般是这样,在单独的模块中调用 React.createCotext 得到 Context,然后把 Context.Provider和Context.Consumer 导出备用。

Provider and Consumer 以组件的形式提供对应的功能

<Provider value={title: '', content: ''}>
  <Title />
  <Content />
 </Provider>
<Consumer>
  {value => <div>{value.title}</div>}
</Consumer>

要注意的是 Consumer 组件的子元素得是一个函数,此函数返回一个组件

3、更通用的解决方案-Redux

Redux 像是一个公共的数据银行,每个组件都可以通过特定的手段与之交互以便存取数据,这些个特定手段就是 store/reducer/action ,

组件发送 action , 然后交由 reducer 处理,reducer 依据提前制订好的规则操作 store ,变化后的 store 再引起组件更新。

落实到编码上:

import {createStore} from 'redux'

const reducer = (state,action)=>{...state,state1:'',state2:''};
const defaultState = {};
const store = createStore(reducer,defaultState);
// store.dispatch(action) 发送数据操作请求
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值