React设计思想

UI=f(data)XUI = f(data)XUI=f(data)X

  1. 在React中,界面完全由数据驱动
  2. 在React中,一切都是组件
    • 用户界面就是组件
    export default function Button {}
    
    • 组件可以嵌套包装,组成复杂功能
    • 组件可以用来实现副作用(ajax、修改dom、埋点等)
  3. props是组件间通讯的基本方式,还有context,redux,event bus等

定义清晰可维护的接口

设计原则

  • 保持接口小,props属性少

  • 合理拆分组件,根据数据边界划分组件,充分组合

  • 把state往上层组件提取,让下层组件只需要实现为纯函数

  • 保持小的更新,细粒度且合理拆分组件,react的diff比对是以组件为单位进行的

最佳实践

  • 避免render函数,访问同样的props和state,代码依然耦合在一起
  • 命名:给回调类型的函数加统一前缀 on开头 (onStart, onSubmit)
  • 对参数定义类型约束
import PropTypes from 'prop-types'
const ControlButton=(props)=>{//todo
}
ControlButton.propTypes={height: PropTypes.number,content: PropTypes.string.isRequired
}

组件内部实现

功能正常、代码整洁、高性能

1. 组件代码拆分

每个组件都有自己专属的代码文件

const BaseInfo = (props) => {
};export default BaseInfo;

代码整洁,易维护,组件互不影响

2. 用解构赋值获取props的属性

const BaseInfo = ({activated, onStart, onPause, onReset, onSplit}) => {}

简化代码,参数一目了然,默认值

3. class组件,利用属性初始化定义state和成员函数

class SellInfo extends React.Component {//this.state, this.onClick=this.onClick.bind(this)state = {isStarted: false,}onClick = () => {this.setState({isStarted: true,});}
}

好看且性能好,保留this

组件设计模式

  • 傻瓜组件和聪明组件
  • hoc模式
  • render props模式
  • 提供者模式
  • 组合模式

1. 聪明组件和傻瓜组件

  • 别名:

    • 有状态组件和无状态组件
    • 容器组件和渲染组件
  • 优点

    • 责任分离, 聪明组件负责管理数据状态,傻瓜组件负责展示数据
    • 如果要优化界面,只需要去修改傻瓜组件,如果想改进数据管理和获取,修改聪明组件

2. 聪明组件和傻瓜组件:提升性能

  • class: PureComponent,实现shouldComponentUpdate浅比较

  • hoc:React.memo

  • hooks: useMemo, useCallback

2.1 React.memo

  • 默认情况浅层比较,传入第二个参数,可自定义深层比较
function MyComponent(props) {/* render using props */
}
function areEqual(prevProps, nextProps) {/*return true if passing nextProps to render would returnthe same result as passing prevProps to render,otherwise return false*/
}
export default React.memo(MyComponent, areEqual);

2.2 useMemo

  • 第二个参数为依赖项,执行回调函数
export default (props = {}) => {console.log(`--- component re-render ---`);return useMemo(() => {console.log(`--- useMemo re-render ---`);return <div>{/* <p>step is : {props.step}</p> */}{/* <p>count is : {props.count}</p> */}<p>number is : {props.number}</p></div>}, [props.number]);
}

2.3 useCallback

  • useCallback 缓存钩子函数,useMemo 缓存返回值
const isEvenNumber = useMemo(() => {return count % 2 === 0;}, [count]);const onClick = useCallback(() => {setCount(count + 1);}, [count]);return (<div><div>{count} is {isEvenNumber ? 'even':'odd'} number</div><button onClick={onClick}></button></div>);

3. hoc模式

const OrderList = () => {if (getUserId()) {return ...; // 显示订单列表} else {return null;}
};
const ProductList = () => {if (getUserId()) {return ...; // 显示商品列表} else {return null;}
};

3.1 hoc模式:抽取共同逻辑,强化组件

const withAuth = (Component) => {//强化操作const NewComponent = (props) => {if (getUserId()) {return <Component {...props} />;} else {return null;}}return NewComponent;
};
const OrderList = withAuth((props) => {return ...; // 显示订单列表
});

3.1 hoc特点

  • 高阶组件是一个纯函数,传入组件,返回一个新的组件,包含参数组件。
  • 高阶组件不能去修改作为参数的组件,一般把传给自己的 props 转手传递给作为参数的组件
  • 命名一般以with开头
  • 使用场景
    • 权限控制,统一对页面进行权限判断,按不同条件渲染不同内容
    • 代码复用,可以将重复的逻辑进行抽象

3.2 hoc优缺点

  • 优点

    • 抽离和复用逻辑
    • 条件渲染,控制渲染等
  • 缺点
    • 组件多层嵌套, 增加复杂度与理解成本,相同命名的props会覆盖老属性,不清楚props来源
    //假如this.props中含有name
    const newProps = {name: "cqm",value: "testData"}
    return <ComponentClass {...this.props} {...newProps} />
    

4. render props 模式

  • props作为函数的参数来渲染部分页面
const RenderAll = (props) => {return(<React.Fragment>{props.children(props)}</React.Fragment>);
};
<RenderAll>() => <h1>hello world</h1>}
</RenderAll>

4.1 传递props

const Login = (props) => {const userName = getUserInfo();if (userName) {const allProps = {userName, ...props};return {props.children(allProps)};} else {return null;}
};<Login>{({userInfo}) => <h1>Hello {userName}</h1>}
</Login>

4.2 不局限于children

const Auth= (props) => {const userName = getUserName();if (userName) {const allProps = {userName, ...props};return {props.login(allProps)};} else {retrun {props.nologin(props)}}
};
<Authlogin={({userName}) => <h1>Hello {userName}</h1>}nologin={() => <h1>Please login</h1>}
/Auth>

4.3 依赖注入

  • 逻辑A依赖于逻辑B和C(A->B、A->C )。依赖注入就是把 B 的逻辑以函数形式传递给 A,A 和 B 达成函数接口一直,逻辑C也可以重用逻辑 A。
  • Login 和 Auth相当于逻辑 A,而传递给组件的函数类型 props,就是逻辑 B 和 C

4.4 和高阶组件的比较

  • props命名可修改,不存在相互覆盖
  • 清楚props来源
  • 比高阶组件更加灵活和简单
  • 不会出现组件多层嵌套,但存在函数回调形式的多层嵌套

5. 提供者模式

场景:假如组件A和组件X之间隔着多层组件,需要传递数据,一层一层传递太麻烦,对于这种跨组件的数据传递,需要提供者模式

5.1 Provider

  • Provider 用于提供 context
//创建context
const ThemeContext = React.createContext();
//提供者
function ThemeProvider(){const theme = { color:'pink' }return <ThemeContext.Provider value={ theme } ><Index /></ThemeContext.Provider>
}

5.2 Consumer

  • Consumer 用于消费 context ,render children 函数中第一个参数就是保存的 context
function ThemeConsumer(props){return <ThemeContext.Consumer>{ (theme)=>{ /* render children函数 */const { color } = themereturn <p style={{color }}>{props.children}</p>} }</ThemeContext.Consumer>
}

5.2 提供者模式原理

  • 通过 Consumer 订阅 context 变化,context 改变,订阅者状态更新
  • 使用场景:全局传递状态、保存状态、外层组件项内层组件传值。

6. 组合模式

  • 组合模式适合一些容器组件场景,通过外层组件包裹内层组件

  • 这种方式在 Vue 中称为 slot 插槽,外层组件可以轻松的获取内层组件的 props 状态,还可以控制内层组件的渲染,

  • 组合模式能够直观反映出 父 -> 子组件的包含关系

6.1 组合模式实例

  <Tabs onChange={ (type)=> console.log(type)  } ><TabItem name="react"  label="react" >React</TabItem><TabItem name="vue" label="vue" >Vue</TabItem><TabItem name="angular" label="angular"  >Angular</TabItem></Tabs>
  • Tabs 负责展示和控制对应的 TabItem 。绑定切换 tab 回调方法 onChange。当 tab 切换的时候,执行回调。

  • TabItem 负责展示对应的 tab 项,向 Tabs 传递 props 相关信息。

6.2 组合模式的原理

  • 在容器组件中通过props.children获取子组件的children,做进一步处理

  • 可以对子组件做类型判断、容器的props混入子组件、子组件传入props的判断控制渲染

  • 既然可以混入容器组件的props,进而可以传递方法参数组件通信

也欢迎加入微信群交流学习点击加入

React组件设计模式与最佳实践相关推荐

  1. react 设计模式与最佳实践

    本文是阅读米凯莱·贝尔托利 <React设计模式与最佳实践> 一书的读书笔记,支持作者请点这里购买. Take is cheap, just show me the code. 废话不少说 ...

  2. pyqt 获取 UI 中组件_你想知道的React组件设计模式这里都有(上)

    本文梳理了容器与展示组件.高阶组件.render props这三类React组件设计模式 往期回顾:HBaseCon Asia 2019 Track 3 概要回顾 随着 React 的发展,各种组件设 ...

  3. Talend“作业设计模式”和最佳实践

    作为Talend开发者,不管是入门新手还是资深人士,常常要处理同一个的问题:"在编写这项作业时,哪种方式最好?"我们知道,通常应当高效.易读易写,并且尤其(多数情况下)要易于维护. ...

  4. 创建设计模式 - Singleton设计模式(最佳实践与示例)

    Java Singleton设计模式最佳实践与示例 Java Singleton Pattern是四种帮派设计模式之一,属于创建设计模式类别.从定义来看,它似乎是一个非常简单的设计模式,但是当涉及到实 ...

  5. hooks组件封装 react_react-hooks amp; context 编写可复用react组件的一种实践

    在新context API出来的时候,就已经有人提出可以用context进行状态管理.react-hooks的更新,使得这一想法的实现更为方便.以一个例子组件进行分析. 前置条件:阅读过react官方 ...

  6. React styled-components TypeScript 的最佳实践

    styled-components + TypeScript 需要安装 @types yarn add -D @types/styled-components 详细说明 原生dom使用 styled. ...

  7. React简单表单最佳实践

    从一个简单表单谈起 假设我们要做一个表单,比如是这样,要怎么做? 你可能会这样写:firstName对应一个键盘记录,lastName对应一个键盘记录: import React from 'reac ...

  8. Android组件化方案最佳实践

    舞动着键盘和鼠标,我誓言要把这个世界写的明明白白 本文出自门心叼龙的博客,属于原创类容,转载请注明出处.https://blog.csdn.net/geduo_83/article/details/8 ...

  9. react项目中的参数解构_重构复杂的React组件:编写高效且可读组件的5个最佳实践...

    随着 React.js 的不断进化,现在的它已经成为 Web 组件中最受欢迎的视图库之一.但是你手中的它,是否真的能够正常工作呢?本文将主要描述 5 个关于React 组件的最佳实践,希望对正在关注 ...

最新文章

  1. A*算法 javascript模拟
  2. pyqt5中QWidget的show 一闪而过的原因及解决办法实例
  3. 【实践】阿里妈妈流量反作弊算法实践
  4. integer超出范围_BigInteger:可以让超过Integer范围内的数据进行运算
  5. MinGw编译opencv教程
  6. Calendar类、自定义实现日历控件
  7. ps 透明底和改变颜色
  8. 免费错别字检测、在线纠错工具
  9. uc视频解析去水印原理分析及源码,集齐四大参数,兑换UC视频播放地址
  10. 机器学习实战——逻辑回归和线性判别分析
  11. _DataStructure_C_Impl:求图G中从顶点u到顶点v的一条简单路径
  12. TSC打印机使用教程终极版
  13. 【RTT】SPI Flash 与文件系统(3):DFS 和 EasyFlash
  14. 如何用Yii2编程:ActiveRecord
  15. 如192.168.1.10/27 IP斜杠后面的27是什么意思?
  16. 2015070304 - EffactiveJava笔记 - 第54条 谨慎使用本地方法
  17. Java初学者问道:Java IDE选择
  18. Linux系统安装盘制作
  19. 欧盟更新玩具安全指令 2009/48/EC 协调标准
  20. 生活不止诗和远方,还有​眼前的苟且!

热门文章

  1. MATLAB 进度条
  2. 数据安全防脱库解决方案信息泄密根源
  3. JAVA反序列漏洞原理及利用工具
  4. 如何免费批量压缩PDF文档?
  5. 面向对象 公司面试题
  6. android 11.0 设置上网应用白名单(上网app白名单)
  7. 火狐如何支持swf格式视频
  8. 音悦 ~ 一款PWA版的在线音乐APP
  9. unity通过脚本实现漫游功能 wasd控制玩家移动,空格跳跃,鼠标控制视野旋转,滑轮控制镜头伸缩
  10. JS 打印 data数据_寒冬求职季之你必须要懂的原生JS(中)