React组件设计模式与最佳实践
React设计思想
UI=f(data)XUI = f(data)XUI=f(data)X
- 在React中,界面完全由数据驱动
- 在React中,一切都是组件
- 用户界面就是组件
export default function Button {}
- 组件可以嵌套包装,组成复杂功能
- 组件可以用来实现副作用(ajax、修改dom、埋点等)
- 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组件设计模式与最佳实践相关推荐
- react 设计模式与最佳实践
本文是阅读米凯莱·贝尔托利 <React设计模式与最佳实践> 一书的读书笔记,支持作者请点这里购买. Take is cheap, just show me the code. 废话不少说 ...
- pyqt 获取 UI 中组件_你想知道的React组件设计模式这里都有(上)
本文梳理了容器与展示组件.高阶组件.render props这三类React组件设计模式 往期回顾:HBaseCon Asia 2019 Track 3 概要回顾 随着 React 的发展,各种组件设 ...
- Talend“作业设计模式”和最佳实践
作为Talend开发者,不管是入门新手还是资深人士,常常要处理同一个的问题:"在编写这项作业时,哪种方式最好?"我们知道,通常应当高效.易读易写,并且尤其(多数情况下)要易于维护. ...
- 创建设计模式 - Singleton设计模式(最佳实践与示例)
Java Singleton设计模式最佳实践与示例 Java Singleton Pattern是四种帮派设计模式之一,属于创建设计模式类别.从定义来看,它似乎是一个非常简单的设计模式,但是当涉及到实 ...
- hooks组件封装 react_react-hooks amp; context 编写可复用react组件的一种实践
在新context API出来的时候,就已经有人提出可以用context进行状态管理.react-hooks的更新,使得这一想法的实现更为方便.以一个例子组件进行分析. 前置条件:阅读过react官方 ...
- React styled-components TypeScript 的最佳实践
styled-components + TypeScript 需要安装 @types yarn add -D @types/styled-components 详细说明 原生dom使用 styled. ...
- React简单表单最佳实践
从一个简单表单谈起 假设我们要做一个表单,比如是这样,要怎么做? 你可能会这样写:firstName对应一个键盘记录,lastName对应一个键盘记录: import React from 'reac ...
- Android组件化方案最佳实践
舞动着键盘和鼠标,我誓言要把这个世界写的明明白白 本文出自门心叼龙的博客,属于原创类容,转载请注明出处.https://blog.csdn.net/geduo_83/article/details/8 ...
- react项目中的参数解构_重构复杂的React组件:编写高效且可读组件的5个最佳实践...
随着 React.js 的不断进化,现在的它已经成为 Web 组件中最受欢迎的视图库之一.但是你手中的它,是否真的能够正常工作呢?本文将主要描述 5 个关于React 组件的最佳实践,希望对正在关注 ...
最新文章
- A*算法 javascript模拟
- pyqt5中QWidget的show 一闪而过的原因及解决办法实例
- 【实践】阿里妈妈流量反作弊算法实践
- integer超出范围_BigInteger:可以让超过Integer范围内的数据进行运算
- MinGw编译opencv教程
- Calendar类、自定义实现日历控件
- ps 透明底和改变颜色
- 免费错别字检测、在线纠错工具
- uc视频解析去水印原理分析及源码,集齐四大参数,兑换UC视频播放地址
- 机器学习实战——逻辑回归和线性判别分析
- _DataStructure_C_Impl:求图G中从顶点u到顶点v的一条简单路径
- TSC打印机使用教程终极版
- 【RTT】SPI Flash 与文件系统(3):DFS 和 EasyFlash
- 如何用Yii2编程:ActiveRecord
- 如192.168.1.10/27 IP斜杠后面的27是什么意思?
- 2015070304 - EffactiveJava笔记 - 第54条 谨慎使用本地方法
- Java初学者问道:Java IDE选择
- Linux系统安装盘制作
- 欧盟更新玩具安全指令 2009/48/EC 协调标准
- 生活不止诗和远方,还有​眼前的苟且!