React的组件协同使用实现方式

目录
  • 嵌套
  • 父子组件通信
  • 兄弟组件通信
  • 抽离
  • Mixin
  • React的LinkedStateMixin
  • Reference:

开发人员不用太过于关注UI层面的实现细节,考虑最多的也就是组件与组件之间的数据通信了。那么,在React开发中,有哪些场景的组件协同?又如何去实现组件的协同使用呢?

组件的协同本质上是对组件的一种组织、管理方式。

目的是使得系统 逻辑清晰、代码模块化、封装细节、代码可复用。

组件的协同分为两种方式:嵌套、抽离、发布订阅模式。

嵌套

组件嵌套的本质就是父子关系,即为父组件和子组件之间的通信。

总的来说有两种场景:

  • 父子组件通信
  • 兄弟组件通信

父子组件通信

首先我们先来看看最常用的一个手段,通过props属性。以父子组件为例,父组件只需要将数据以props的方式传递给子组件,子组件可以直接通过this.props来获取,比如:

// 父组件 Parent
export default class Parent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      message: '传给子组件的消息'
    }
  }

  // 消息回调
  onMessage(messageFromChildren) {
    console.log(messageFromChildren);
  }

  render() {
    const { message } = this.state;
    return (
      <div>
        <Children message={ message } onMessage={ this.onMessage.bind(this) } />
      </div>
    );
  }
}
// 子组件 Children
export default class Children extends React.Component {
  constructor(props) {
    super(props);
  }

  handleClick() {
    this.props.onMessage('来自子组件的消息');
  }

  render() {
    const { message } = this.props;
    return (
      <div>
        <p>{ message }</p>
        <button onClick={ this.handleClick.bind(this) }>click</button>
      </div>
    );
  }
}

当然,如果Children子组件需要传递数据给到父组件,可以使用回调方式,父组件将方法的引用通过props传递给到子组件,如上代码中的handleClick里调用了onMessage。当父组件的state更新时,Children组件会重新渲染,使用最新的message数据。

bind的作用就是给函数增加默认的参数,第一个传参将替代方法里面的this

兄弟组件通信

兄弟组件不能直接相互通信,需要通过父组件来中转一下,进行状态提升。兄弟组件将需要共享的数据提升至共同的直接父组件中,然后就跟普通的父子组件通信一样了。比如:

// 父组件 Parent
export default class Parent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      messageFromA: '',
      messageFromB: ''
    }
  }

  onMessage(messageFromChildren, from) {
    console.log(messageFromChildren);

    this.setState({
      [from == 'A' ? 'messageFromA' : 'messageFromB']: messageFromChildren
    });
  }

  render() {
    const { messageFromA,  messageFromB} = this.state;
    return (
      <div>
        <ChildrenA message={ messageFromB } onMessage={ this.onMessage.bind(this) } />
        <ChildrenB message={ messageFromA } onMessage={ this.onMessage.bind(this) } />
      </div>
    );
  }
}
// 子组件ChildrenA
export default class ChildrenA extends React.Component {
  constructor(props) {
    super(props);
  }

  handleClick() {
    this.props.onMessage('来自A子组件的消息', 'A');
  }

  render() {
    const { message } = this.props;
    return (
      <div className="p-a b-a">
        <p>{ message }</p>
        <button onClick={this.handleClick.bind(this)}>clickA</button>
      </div>
    );
  }
}
// 子组件 ChildrenB
export default class ChildrenB extends React.Component {
  constructor(props) {
    super(props);
  }

  handleClick() {
    this.props.onMessage('来自B子组件的消息', 'B');
  }

  render() {
    const { message } = this.props;
    return (
      <div className="p-a b-a">
        <p>{ message }</p>
        <button onClick={this.handleClick.bind(this)}>clickB</button>
      </div>
    );
  }
}

当点击clickA的时候,子组件B接收到了子组件A的消息,反之亦然。

通过props的组件通信比较简单,但也有其自身的缺陷,当组件层级大于3层时,这种方式就不适合了,首先是深层级的传递对到维护来说简直就是噩梦,需要一层一层的看才能知道数据的来源及流向。其次的话,假如不止A、B子组件,还有C子组件的,A、B组件引发的父组件state更新会触发C子组件的更新,但事实上,C子组件并没有接收任何数据,容易造成资源浪费。

// Parent组件
  render() {
    const { messageFromA,  messageFromB} = this.state;
    return (
      <div>
        <ChildrenA message={ messageFromB } onMessage={ this.onMessage.bind(this) } />
        <ChildrenB message={ messageFromA } onMessage={ this.onMessage.bind(this) } />
        <ChildrenC />
      </div>
    );
  }
// 子组件 ChildrenC
export default class ChildrenC extends React.Component {
  constructor(props) {
    super(props);
  }

  componentDidUpdate() {
    console.log('ChildrenC updated');
  }

  render() {
    return (
      <div>ChildrenC</div>
    );
  }
}

抽离

Mixin

这里要介绍的抽离主要是指Mixin。

假设有多个组件使用相同的getDefaultProps方法,我们就可以定义如下Mixin:

var DefaultNameMixin = {
    getDefaultProps: function () {
        return {name: "Tom"};
    }
};

Mixin相当于组件的一个扩展,它的本质就是一组方法的集合,使用这个 mixin 的组件能够自由的使用这些方法(就像在组件中定义的一样)。使用Mixin的目的就是横向抽离出组件的相似代码。

与Mixin思路相似的概念还有:AOP、插件等

例子中,DefaultNameMixin中包含getDefaultProps方法。除了直接定义外,Mixin还可以嵌套使用,也就是可以在定义Mixin时使用另一个Mixin:

var DefaultCommonMixin = {
    mixins:[DefaultNameMixin], //use Mixin
    getDefaultProps: function () {
        return {food: "rice"};
    }
};

例子中,在DefaultCommonMixin的定义中嵌套使用了DefaultNameMixin,因此DefaultCommonMixin包含了DefaultNameMixin中定义的getDefaultProps方法,此时DefaultCommonMixin中有两个方法。使用Mixin时,只需将Mixin加入到mixins属性对应的数组中,Mixin的使用语法为mixins:[Mixin1,Mixin2……]。

使用Mixin时,只需将Mixin加入到mixins属性对应的数组中,Mixin的使用语法为mixins:[Mixin1,Mixin2……]。

var Component = React.createClass({
    mixins:[DefaultCommonMixin], //use Mixin
    render:function(){
        return <h1>{this.props.name} like {this.props.food}</h1>;
    }
}); 

ReactDOM.render(
    <Component/>,
    document.getElementById("example")
);

一个组件可以使用多个Mixin,同时,Mixin也可使用在多个组件中。

使用Mixin时,需要注意不要在多个地方设置相同的Prop和State。同时,在不同的Mixin中定义相同的方法,或者Mixin和组件中包含了相同的方法时,也会抛出异常,但是这种情况对componentDidMount等生命周期方法不适用(render方法除外,多次定义render方法也会抛出异常)。

如果在一个组件的多个地方定义了相同的生命周期方法,这些方法的执行顺序为:Mixin中的方法会优先执行(根据mixins中的顺序从左到右的顺序),然后执行组件中定义的方法。

Mixin的优点:

代码复用:抽离出通用代码,减少开发成本,提高开发效率

即插即用:可以直接使用许多现有的Mixin来编写自己的组件

适应性强:改动一次代码,影响多个组件

Mixin的缺点:

编写难度高:Mixin可能被用在各种环境中,兼容多种环境就需要更多的逻辑和代码,通用的代价是提高复杂度。

降低代码可读性:组件的优势在于将逻辑和界面直接结合在一起,Mixin本质上会分散逻辑,理解起来难度更大。

React的LinkedStateMixin

'use strict';  

// 构建对象{value,requestChange},value为初始值,requestChange为方法,须手动调用
// 在本模块中,value为state[key]的初始值,requestChange用于更新state[key]
var ReactLink = require('./ReactLink');  

// 设定属性key后,返回函数,该函数接受value,内部调用组件component.setState方法,更新state[key]=value
var ReactStateSetters = require('./ReactStateSetters');  

/**
 * 针对react手动调用setState方法的单向数据流,提供双向绑定
 * 使用linkState(key).requestChange(value)传值后自动调用setState方法,更新state
 *
 * 示例
 * var LinkedStateMixin = require('react-addons-linked-state-mixin'); 

 * var WithoutLink = React.createClass({
 *   mixins: [LinkedStateMixin],
 *   getInitialState: function() {
 *     return {message: 'Hello!'};
 *   },
 *   render: function() {
 *     var valueLink = this.linkState('message');
 *     var handleChange = function(e) {
 *       valueLink.requestChange(e.target.value);
 *     };
 *     return <input type="text" value={valueLink.value} onChange={handleChange} />;
 *   }
 * });
 */
var LinkedStateMixin = {
  // ReactStateSetters.createStateKeySetter方法用于构建linkState(key)返回对象的requestChange方法
  // 实现传值后自动调用setState方法,更新state
  linkState: function (key) {
    return new ReactLink(this.state[key], ReactStateSetters.createStateKeySetter(this, key));
  }
};  

module.exports = LinkedStateMixin;  

使用上述的Mixin:

import LinkedStateMixin from 'react-addons-linked-state-mixin'

mixins: [React.addons.LinkedStateMixin],

LinkedStateMixin仅仅是一个onChange/setState()模式的简单包装和约定。它不会从根本上改变数据在你的React应用中如何流动,也就是说其实LinkedStateMixin本质还是单向流,只是通过onChange将数据更改传递给React,然后内部数据改变就自动调用setState来进行更新。

使用示例:

var WithLink = React.createClass({
  mixins: [LinkedStateMixin],
  getInitialState: function() {
    return {message: 'Hello!'};
  },
  render: function() {
    return <input type="text" valueLink={this.linkState('message')} />;
  }
});

LinkedStateMixin给你的React组件添加一个叫做linkState()的方法。linkState()返回一个包含React state当前的值和用来改变它的回调函数的valueLink对象。

valueLink 对象可以在树中作为props被向上传递或者向下传递,所以它在组件层和状态层建立起双向绑定是非常简单的。

注意:

对于checkboxvalue属性,有一个特殊的行为,如果checkbox被选中(默认是on),value属性值将会在表单提交的时候发送出去。当checkbox被选中或者取消选中的时候,value属性是不会更新的。对于checkbox,你应该使用checkLink而不是valueLink

<checkbox type="checkbox" checkedLink={this.linkState('booleanValue')} />

Reference:

1. http://schifred.iteye.com/blog/2361478

2. http://blog.csdn.net/qq_18661257/article/details/68951561

到此这篇关于React的组件协同使用的文章就介绍到这了,更多相关React组件协同内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • React实现动效弹窗组件

    我们在写一些 UI 组件时,若不考虑动效,就很容易实现,主要就是有无的切换(类似于 Vue 中的 v-if 属性)或者可见性的切换(类似于 Vue 中的 v-show 属性). 1. 没有动效的弹窗 在 React 中,可以这样来实现: interface ModalProps { open: boolean; onClose?: () => void; children?: any; } const Modal = ({open. onClose, children}: ModalProps)

  • React如何创建组件

    前言 这节我们将介绍 React 中组件的类别,以及如何创建和使用组件. 本文会向你介绍以下内容: 创建类组件 创建函数组件 渲染组件 合成组件 提取组件 Props 是只读的 组件介绍 组件(Components) 让你可以将用户界面分成独立的,可复用的小部件,并可以对每个部件进行单独的设计. 从定义上来说, 组件就像JavaScript的函数.组件可以接收任意输入(称为"props"), 并返回 React 元素,用以描述屏幕显示内容. Props , 即属性(Property),

  • React星星评分组件的实现

    实现的需求为传入对商品的评分数据,页面显示对应的星星个数. 1. 准备三张对应不同评分的星星图片 2. 期望实现的效果 这样的 调用 <StarScore score={data.wm_poi_score}/> 3. 对传入的数据进行处理 我们需要得到评分的整数和小数部分 let wm_poi_score = this.props.score || ''; let score = wm_poi_score.toString(); let scoreArray = score.split('.'

  • React的组件协同使用实现方式

    目录 嵌套 父子组件通信 兄弟组件通信 抽离 Mixin React的LinkedStateMixin Reference: 开发人员不用太过于关注UI层面的实现细节,考虑最多的也就是组件与组件之间的数据通信了.那么,在React开发中,有哪些场景的组件协同?又如何去实现组件的协同使用呢? 组件的协同本质上是对组件的一种组织.管理方式. 目的是使得系统 逻辑清晰.代码模块化.封装细节.代码可复用. 组件的协同分为两种方式:嵌套.抽离.发布订阅模式. 嵌套 组件嵌套的本质就是父子关系,即为父组件和

  • 详解React中组件之间通信的方式

    一.是什么 我们将组件间通信可以拆分为两个词: 组件 通信 回顾Vue系列的文章,组件是vue中最强大的功能之一,同样组件化是React的核心思想 相比vue,React的组件更加灵活和多样,按照不同的方式可以分成很多类型的组件 而通信指的是发送者通过某种媒体以某种格式来传递信息到收信者以达到某个目的,广义上,任何信息的交通都是通信 组件间通信即指组件通过某种方式来传递信息以达到某个目的 二.如何通信 组件传递的方式有很多种,根据传送者和接收者可以分为如下: 父组件向子组件传递 子组件向父组件传

  • 详解react hooks组件间的传值方式(使用ts)

    目录 父传子 子传父 跨级组件(父传后代) 父传子 通过props传值,使用useState来控制state的状态值 父组件 Father.tsx里: 子组件 Child.tsx里: 展示效果: 子传父 跟react的方式一样,像子组件传入回调函数,通过接收子组件的返回值,再去更新父组件的state 父组件,Father.tsx里: 子组件,Child.tsx里: 展示效果: 子传父优化版,使用useCallback存放处理事件的函数 父组件,Father.tsx里: 子组件,Child.tsx

  • React构建组件的几种方式及区别

    目录 一.组件是什么 二.如何构建 函数式创建 通过 React.createClass 方法创建 继承 React.Component 创建 三.区别 一.组件是什么 组件就是把图形.非图形的各种逻辑均抽象为一个统一的概念(组件)来实现开发的模式 在React中,一个类.一个函数都可以视为一个组件 组件所存在的优势: 降低整个系统的耦合度,在保持接口不变的情况下,我们可以替换不同的组件快速完成需求,例如输入框,可以替换为日历.时间.范围等组件作具体的实现 调试方便,由于整个系统是通过组件组合起

  • React路由组件三种传参方式分析讲解

    目录 路由组件和组件的区别 Swith内置组件使用 react 路由传参 编程式导航 Redirect重定向 路由组件和组件的区别 路由组件时被Router组件使用的组件,this.props里面有三个参数,分别是history.match.location 可以接收到路由跳转传参,也可以进行编程式导航跳转 普通组件只有父传子的props值 Swith内置组件使用 作用:当匹配一个路由组件时,其他组件不会被使用,可以加入404页面,给用户进行友好提示,提升用户体验 react 路由传参 方式一:

  • React创建组件的三种方式及其区别

    React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归:具体的三种方式: 函数式定义的无状态组件 es5原生方式React.createClass定义的组件 es6形式的extends React.Component定义的组件 虽然有三种方式可以定义react的组件,那么这三种定义组件方式有什么不同呢?或者说为什么会出现对应的定义方式呢?下面就简单介绍一下. 无状态函数式组件 创建无状态函数式组件形式是从React 0.14版本开始出现的.它是为了创建纯展示组件,这种组件

  • 浅谈React中组件间抽象

    关于今天要学习的组件间抽象其实我这小白看了几次还没弄明白,这次决定一探究竟.在组件构建中,通常有一类功能需要被不同的组件公用,此时就涉及抽象的概念,在React中我们主要了解mixin和高阶组件. mixin mixin的特性广泛存在于各个面向对象语言中,在ruby中,include关键词就是mixin,是将一个模块混入到另外一个模块中,或者是类中. 封装mixin方法 const mixin = function(obj, mixins) { const newObj = obj newObj

  • 关于react中组件通信的几种方式详解

    前言 刚入门React可能会因为React的单向数据流的特性而遇到组件间沟通的麻烦,下面这篇文章就来给大家详细介绍下,在开始之前先来看一张图: react组件通信 需要组件之进行通信的几种情况 父组件向子组件通信 子组件向父组件通信 跨级组件通信 没有嵌套关系组件之间的通信 1. 父组件向子组件通信 React数据流动是单向的,父组件向子组件通信也是最常见的;父组件通过props向子组件传递需要的信息 Child.jsx import React from 'react'; import Pro

  • Vue和React组件之间的传值方式详解

    在现代的三大框架中,其中两个Vue和React框架,组件间传值方式有哪些? 组件间的传值方式 组件的传值场景无外乎以下几种: 父子之间 兄弟之间 多层级之间(孙子祖父或者更多) 任意组件之间 父子之间 Vue Vue是基于单项数据流设计的框架,但是提供了一些的语法,指令去实现一些操作 父->子:通过props进行传递数据给子组件 子->父:通过emit向父组件传值 同时,还有一些其他进行父子组件通信的方式,通过$parent和$children获取组件的父或者子组件的实例,之后通过实例对象去修

  • React创建组件的的方式汇总

    目录 1. 使用函数创建组件 2. 使用类创建组件 3. 抽离为独立JS文件 1. 使用函数创建组件 函数组件:使用JS的函数(或箭头函数)创建的组件 约定1:函数名称必须以大写字母开头 约定2:函数组件必须有返回值,表示该组件的结构 如果返回值为null,表示不渲染任何内容 function Hello() { return ( <div>这是我的第一个函数组件!</div> ) } const Hello = () => <div>这是我的第一个函数组件!&l

随机推荐