内容简介:提高可读性、可维护性把相关联的东西放一起(按功能、业务)只有render方法、简单的交互事件处理和state管理。比如Input/CheckBox等。
为什么要拆分组件
提高可读性、可维护性
如果不拆分
- 代码量大,所有内容集中在一起
- 相同组件无法复用
- 业务开发分工不明确,开发人员要关心非业务的代码
- 改代码时,可能会影响其他业务,牵一发动全身(耦合)
- 任何一个操作都导致整个应用重新render
目标
- 架构清晰
- 相同组件能够复用
- 业务分工明确,开发人员仅专注与自己的业务
- 每个组件负责独立的功能,与其他组件解耦合
- 可使用SCU、memo减少不必要渲染
如何拆分组件
把相关联的东西放一起(按功能、业务)
- 横向(按业务、功能模块划分)
- 纵向(应用、系统层级划分)
一个React组件的功能
- 维护局部数据: state、ref、后台返回等
- 获取、修改全局数据
- 事件处理、数据监听处理(useEffect/componentDidUpdate等)
- IO: 网络请求/本地读写
- 数据处理
- render
组件分类
展示组件
只有render方法、简单的交互事件处理和state管理。比如Input/CheckBox等。
划分标准: 根据UI稿,不同的展示模块分为不同的组件。比如顶部、底部、导航、列表等
容器组件
业务组件
与数据源(redux/后台/本地存储)进行数据传输操作(不止是IO)
划分标准: 根据业务功能划分。比如登录、登出、支付、表单校验等
连接组件
连接业务组件和展示组件, 主要用于处理数据后传给展示组件。
组件树结构
展示组件内可以有容器组件,容器组件内也可以有展示组件
案例
逻辑、展示分离
把渲染和功能拆分成不同组件,提高复用性
不拆分
登录组件处理了2件事情:
- 渲染登录表单
- 记录用户输入和登录状态,向后台发送登录请求
class Login extends Component { constructor(props) { super(props) this.state = { account: '', password: '', status: 'init', } } handleAccountChange(e) { this.setState({account: e.target.value}) } handlePasswordChange(e) { this.setState({password: e.target.value}) } handleLoginClick() { this.setState({ status: 'ing' }) request('/login', { params: { account: this.state.account, password: this.state.password, } }).then(() => { this.setState({status: 'succ'}) }).catch(() => { this.setState({status: 'fail'}) }) } render() { return ( <div> <input placeholder="账号" value={this.state.account} onChange={(...args) => this.handleAccountChange(...args)} /> <input placeholder="密码" value={this.state.password} onChange={(...args) => this.handlePasswordChange(...args)} /> <button onClick={() => this.handleLoginClick()}>登录</button> </div> ) } }
拆分后
容器组件负责实现登录功能,展示组件负责渲染内容。
如果要实现另一套登陆组件时,可直接复用容器组件,只需要实现新的展示组件即可。
// 业务组件 可复用性比较高 function withLogin(config) { const { mapStateToProps, mapDispatchToProps } = config return (Comp) => { class Container extends Component { constructor(props) { super(props) this.state = { account: '', password: '', status: 'init', } } handleAccountChange = (e) => { this.setState({account: e.target.value}) } handlePasswordChange = (e) => { this.setState({password: e.target.value}) } handleLoginClick = () => { this.setState({ status: 'ing' }) request('/login', { params: { account: this.state.account, password: this.state.password, } }).then(() => { this.setState({status: 'succ'}) }).catch(() => { this.setState({status: 'fail'}) }) } render() { const propsFromState = mapStateToProps(this.state, this.props) const propsFromDispatch = mapDispatchToProps({ onAccountChange: this.handleAccountChange, onPasswordChange: this.handlePasswordChange, onSubmit: this.handleLoginClick, }, this.props) return ( <Comp {...this.props} {...propsFromState} {...propsFromDispatch} /> ) } } return LoginContainer } } // 展示组件 class Login extends Component { render() { const { account, password, onAccountChange, onPasswordChange, onSubmit } return ( <div> <input placeholder="账号" value={account} onChange={(...args) => onAccountChange(...args)} /> <input placeholder="密码" value={password} onChange={(...args) => onPasswordChange(...args)} /> <button onClick={() => onSubmit()}>登录</button> </div> ) } } // 连接组件 const LoginContainer = withLogin({ mapStateToProps: (state, props) => { return { account: state.account, password: state.password, } }, mapDispatchToProps: (dispatch, props) => { return { onAccountChange: dispatch.onAccountChange, onPasswordChange: dispatch.onPasswordChange, onSubmit: dispatch.Submit, } } })
渲染优化
把UI上相互独立的部分,划分成不同组件,防止渲染时相互影响。最常见的是列表组件。
拆分前
点击一个li, 其他li全都重新渲染
class List extends Component { state = { selected: null } handleClick(id) { this.setState({selected: id}) } render() { const { items } = this.props return ( <ul> { items.map((item, index) => { const {text, id} = item const selected = this.state.selected === id return ( <li key={id} className={selected ? 'selected' : ''} onClick={() => this.handleClick(id)} > <span>{text}</span> </li> ) }) } </ul> ) } }
拆分后
子组件使用 PureComponent
或 memo
,并且click事件回调函数直接使用 this.handleClick
,而不是每次都创建新函数。
点击li,最多只会有2个子组件渲染。
// onClick时需要的参数,要传进来 class Item extends PureComponent { render() { const { id, text, selected, onClick } = this.props return ( <li className={selected ? 'selected' : ''} onClick={onClick(id)} > <span>{text}</span> </li> ) } } class List extends Component { state = { selected: null } handleClick(id) { this.setState({selected: id}) } render() { const { items } = this.props return ( <ul> { items.map((item, index) => { const {text, id} = item return ( <Item key={id} id={id} // 传进去 selected={this.state.selected === id} text={text} onClick={this.handleClick} /> ) }) } </ul> ) } }
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- iOS组件化拆分之业务与拆分并行开发
- 微服务的拆分与组件
- styled-components:前端组件拆分新思路
- html – 当我们拆分表时,如何将div拆分为两列?
- 微服务拆分之道
- 微服务的灾难-拆分
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
人人都是产品经理
苏杰 / 电子工业出版社 / 2014-9-1 / CNY 55.00
《人人都是产品经理(纪念版)》为经典畅销书《人人都是产品经理》的内容升级版本。对于大量成长起来的优秀互联网产品经理,为数不少想投身产品工作的其他岗位从业者,以及更多有志从事这一职业的学生而言,这本书曾是他们记忆深刻的启蒙读物、思想基石和行动手册。作者以分享经历与体会为出发点,以“朋友间聊聊如何做产品”的语气,将自己数年产品工作过程中学到的思维方法与做事方式,及其它们对自己的帮助,系统性地梳理为用户......一起来看看 《人人都是产品经理》 这本书的介绍吧!