组件,从概念上类似于 JavaScript 函数。它接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。
  React没有多少API可以用,基本上都是组件来完成一个项目。React的工作方式类似于UI=F(state),即一旦组件维护的state发生改变,render函数就会重新执行,导致试图改变。因此学好React组件是至关重要的。

容器组件VS展示组件

  我们希望尽可能让更多的组件变成傻瓜组件,它只负责将数据展示到视图上,而它所用的数据全部都提升到父级组件。父级组件负责逻辑处理和状态维护,将子组件所需的回调事件和状态通过props传递给子组件。这样单纯的展示组件就会有很好的易用性、复用性和维护性。

import React, { Component } from 'react'//容器组件
export default class BookList extends Component{constructor(props){super(props)this.state = {books:[]}}componentDidMount() {setTimeout(() => {this.setState({books:[{ name: '《你不知道的javascript》', price: 50 },{ name: '《ES6标准入门》', price: 99 } ]})}, 1000)}render(){return(<div>{this.state.books.map((book, index) => <Book key={index} {...book}></Book>)}</div>)}
}//展示组件
function Book({ name, price }){return (<div><p>书名:{name}</p><p>价格:{price}</p></div>  )
}
复制代码

展示组件存在的问题

  上述展示组件存在一个问题,因为React中数据维持着不变性的原则,只要setState改变books,都会触发render函数的调用以及虚拟DOM的比较。如果books中的值只有一条变化,它也会引发每条数据都引发一次render函数调用。我们怎么去规避展示组件无谓的数据消耗和渲染函数的调用呢?首先我们看这段代码:

import React, { Component, PureComponent } from 'react'//容器组件
export default class BookList extends Component {constructor(props) {super(props)this.state = {books: []}}componentDidMount () {setTimeout(() => {this.setState({books: [{ name: '《你不知道的javascript》', price: 50 },{ name: '《ES6标准入门》', price: 99 }]})}, 1000)setTimeout(() => {this.setState({books: [{ name: '《哈利波特》', price: 25 },{ name: '《ES6标准入门》', price: 99 }]})}, 2000)}render () {return (<div>{this.state.books.map((book, index) => <Book key={index} {...book}></Book>)}</div>)}
}
// 展示组件
function Book ({ name, price }) {console.log('渲染了')return (<div><p>书名:{name}</p><p>价格:{price}</p></div>)
}
复制代码

  它在浏览器上打的log如下:

  首先由一个空数组变成有两条数据的数组肯定会导致两次render函数调用,但是第二次变化时,只有第一条数据改变,但还是引起了两次render函数的调用。这是因为我们为了维持数据的不变性,每次都会更新books为一个全新的数组。
  我们要明确一点,肯定是要维持数据的不变性的。有三种方法可以规避这种无谓的render的调用。在PureComponent没有出现之前,我们在shouldComponentUpdate这个生命周期钩子函数中比较下一个值和当前值,如果相等,则不需要更新该条数据,返回false,写法比较累赘。React15.3之后出现了PureComponent纯组件,它就是在内部实现了在shouldComponentUpdate中比较值。还有一种是React16.6之后出现的React.memo,与使用PureComponent方法的原理和效果是等价的,它是一个高阶组件。
  用上述方法在浏览器上打的log为:

shouldComponentUpdate
class Book extends Component {shouldComponentUpdate ({ name, price }) {if (this.props.name === name && this.props.price === price) {return false}return true}render () {console.log('渲染了')return (<div><p>书名:{this.props.name}</p><p>价格:{this.props.price}</p></div>)}
}
复制代码
PureComponent
class Book extends PureComponent {render () {console.log('渲染了')return (<div><p>书名:{this.props.name}</p><p>价格:{this.props.price}</p></div>)}
}
复制代码
React.memo
const Book = React.memo(function ({ name, price }) {console.log('渲染了')return (<div><p>书名:{name}</p><p>价格:{price}</p></div>)}
)
复制代码

高阶组件

  上面我们讲到了高阶组件,它是一个函数,接收一个组件,返回一个加强后的组件。组件是将 props 转换为 UI,而高阶组件是将组件转换为另一个组件。高阶组件可以提高组件的复用率,重写生命周期函数。
  基础写法:

import React, { Component } from 'react'
//一个简单的展示组件
function Pure (props) {return (<div>{props.name} -- {props.age}</div>)
}
//高阶组件
const withLog = (Comp) => {console.log(Comp.name + '渲染了')return (props) => {return <Comp {...props}></Comp>}
}
//生成一个新的组件
const NewPure = withLog(Pure)
//使用这个新组件
export default class Hoc extends Component {render () {return (<div><NewPure age='19' name='zhunny'></NewPure></div>)}
}
复制代码

高阶组件的链式调用

  高阶组件可以链式调用,且可以在一个链式调用中调用多次同一个高阶组件。

import React, { Component } from 'react'function Pure (props) {return (<div>{props.name} -- {props.age}</div>)
}const strengthenPure = Comp => {const name = 'zhunny'//返回类组件return class extends React.Component {componentDidMount () {console.log('do something')}render () {return <Comp {...this.props} name={name}></Comp>}}
}const withLog = (Comp) => {console.log(Comp.name + '渲染了')return (props) => {return <Comp {...props}></Comp>}
}//高阶组件可以链式调用
const NewPure = withLog(strengthenPure(withLog(Pure)))
export default class Hoc extends Component {render () {return (<div><NewPure age='19'></NewPure></div>)}
}
复制代码

高阶组件的装饰器写法

  ES7的装饰器可以简化高阶组件的写法,不过需要引入一个转义decorator语法的插件,并在根目录配置config-overrides.js文件。安装react-app-rewired取代react-scripts,可以扩展webpack的配置 ,类似vue.config.js

npm install --save-dev babel-plugin-transform-decorators-legacy
npm install react-app-rewired@2.0.2-next.0 babel-plugin-import --save
复制代码
const { injectBabelPlugin } = require("react-app-rewired");
module.exports = function override (config, env) {//装饰器config = injectBabelPlugin(["@babel/plugin-proposal-decorators", { legacy: true }],config);return config;
};
复制代码

  因为decorator只能装饰类,因此只能装饰基于类的组件。

@withLog
@strengthenPure
@withLog
class Pure extends React.Component {render () {return (<div>{this.props.name} -- {this.props.age}</div>)}
}
复制代码

组件的组合composition

  React 有十分强大的组合模式。我们推荐使用组合而非继承来实现组件间的代码重用。组合组件给予你足够的敏捷去定义自定义组件的外观和行为,而且是以一种明确和安全的方式进行。如果组件间有公用的非UI逻辑,将它们抽取为JS模块导入使用而不是继承它。

包含关系

  有些组件无法提前知晓它们子组件的具体内容。这些组件可以使用一个特殊的 children prop 来将他们的子组件传递到渲染结果中。

function Dialog (props) {return (<div style={{ border: `1px solid ${props.color || "blue"}` }}>{props.children}<footer>{props.footer}</footer></div>)
}//可以看作一个特殊的Dialog
function WelcomeDialog (props) {console.log(props)return (<Dialog {...props}>{/*类似于匿名slot插槽*/}<h1>欢迎光临</h1><p>感谢使用React</p></Dialog>)
}export default function () {//footer类似于具名slot插槽const footer = <button onClick={() => { alert('1') }}>footer</button>return (<WelcomeDialog color='green' footer={footer}></WelcomeDialog>)
}
复制代码

  props.children可以是任意js表达式,可以是一个函数。

const Api = {getUser () {return { name: 'jerry', age: 20 }}
}function Fetcher (props) {const user = Api[props.name]()return props.children(user)
}
export default function () {//类似于作用域插槽return (<Fetcher name="getUser">{({ name, age }) => (<p>{name}-{age}</p>)}</Fetcher>)
}
复制代码

示例

function GroupRadio (props) {//因为props的内容是不可修改的,因此在Radio上增加一个属性需要拷贝一份return <div>{React.Children.map(props.children, child => {return React.cloneElement(child, { name: props.name })})}</div>
}function Radio ({ children, ...rest }) {return (<label><input type="radio" {...rest} />{children}</label>)
}
export default function () {return (<GroupRadio name="mvvm"><Radio value="vue">vue</Radio><Radio value="angular">angular</Radio><Radio value="react">react</Radio></GroupRadio>)
}
复制代码

React(2)之——React组件化相关推荐

  1. React功能界面的组件化编码流程

    功能界面的组件化编码流程(通用) 1.拆分组件: 拆分界面,抽取组件 2.实现静态组件: 使用组件实现静态页面效果 3.实现动态组件 3.1 动态显示初始化数据 3.1.1 数据类型 3.1.2 数据 ...

  2. 深入react技术栈(7):组件化实例:Tab栏组件

    我是歌谣 放弃很容易 但是坚持一定很酷 微信公众号关注前端小歌谣 文章参考深入React技术栈

  3. 【React】项目中组件化使用svg格式的图片

    光の剧场 今日份主演:(

  4. client高性能组件化框架React简单介绍、特点、环境搭建及经常使用语法

    [本文源址:http://blog.csdn.net/q1056843325/article/details/54729657 转载请加入该地址] 明天就是除夕了 预祝大家新春快乐 [ ]~( ̄▽ ̄) ...

  5. 移动web端的react.js组件化方案

     背景: 随着互联网世界的兴起,web前端开发的方式越来越多,出现了很多种场景开发的前端架构体系,也对前端的要求日益增高,早已经不是靠一个JQuery.js来做前端页面的时代了,而今移动端变化最大,近 ...

  6. React.js加载组件以及JSX脚本处理代码

    React.js是一个组件化的JS界面开发库,可以结合XML格式的脚本语法JSX. 如果你的页面中包含了这样的代码,需要将JSX代码预编译为Raw JavaScript,不然会提示有语法错误" ...

  7. 组件化开发实战_一篇文章搞懂什么是前端“组件化”开发

    学过网页的朋友都知道,制作一个网页离不开HTML.CSS和JavaScript技术.对于初学者来来说,掌握这3门技术就已经很不容易了,为什么前端为什么又要搞出来一个"组件化"开发的 ...

  8. 小谈React、React Native、React Web

    React有三个东西,React JS 前端Web框架,React Native 移动终端Hybrid框架,React Web是一个源码转换工具(React Native 转 Web,并之所以特别提出 ...

  9. 16、React系列之 React 路由

    版权声明:本文为博主原创文章,未经博主允许不得转载. PS:转载请注明出处 作者:TigerChain 地址:http://www.jianshu.com/p/b55cf53e633a 本文出自 Ti ...

  10. AlloyTeam:致我们终将组件化的 Web (多图)

    这篇文章将从两年前的一次技术争论开始.争论的聚焦就是下图的两个目录分层结构.我说按模块划分好,他说你傻逼啊,当然是按资源划分. "按模块划分"目录结构,把当前模块下的所有逻辑和资源 ...

最新文章

  1. Mozilla公布WebVR API标准草案
  2. java修改数据库表结构_数据库设计(一):设计传统系统表结构(Java开发)
  3. PYPL 12 月 IDE 榜单:Eclipse 有望超越 Visual Studio
  4. android 根据版本,Android – 根据构建类型更改flavor版本名称
  5. hue安装及基本测试-笔记
  6. winCVS 使用方法
  7. 设计模式的Java 8 Lambda表达式–命令设计模式
  8. JS中Promise函数then的奥秘探究
  9. keybd_event、SendInput笔记
  10. pytorch保存模型参数
  11. 企业数据安全防护不可忽视,数据丢失/损坏如何处理?
  12. 十六、Java四种内部类详解、匿名对象的使用
  13. C语言头歌educoder实训作业答案分享 结构体
  14. Aqua Data Studio v19.0 安装使用
  15. 【Proteus仿真】51单片机+红外测距仪(GP2D12)+ADC0809模数转换
  16. java 图片识别_java实现图片文字识别的两种方法
  17. 经典数字电路 设计案例
  18. HSA-TPP 人血清白蛋白-磷酸三苯酯,HSA-PEG-TPP
  19. 两数之和——python
  20. The annotation of C++ primer {藤原豆腐坊自家用}

热门文章

  1. iview组件 eslint校验出错 Parsing error: x-invalid-end-tag
  2. Eigen中的map
  3. 网页设计基础知识总结
  4. wordpress页面前端添加编辑按钮
  5. jenkins, docker-composer
  6. unity 相机的问题
  7. 用c#中的WebBrowser抢小米F码,抢小米手机以及自动测试实现原理
  8. 谈恋爱、结婚的5种境界
  9. Java开发笔记(一百二十八)Swing的图标
  10. DcotrineFixtureBundle学习