React 的组件很是的
灵活可扩展
,不过随着业务复杂度的增长和许多外部工具库的引入,组件每每也会显得浮肿
,接下来咱们就一块儿来看看常见的几种,遵循单一职责原则
的,组件分割与解耦
的方法javascript
当一个组件渲染的内容较多时,有一个快速而且通用的方法是建立sub-render
函数来简化原来庞大的 renderjava
class Panel extends React.Component { renderHeading() { // ... } renderBody() { // ... } render() { return ( <div> {this.renderHeading()} {this.renderBody()} </div> ); } }
为了再次简化sub-render
函数,咱们还能够采用Functional Components
写法,这种方式生成了更小的处理单元,且更有利于测试node
const PanelHeader = (props) => ( // ... ); const PanelBody = (props) => ( // ... ); class Panel extends React.Component { render() { return ( <div> // Nice and explicit about which props are used <PanelHeader title={this.props.title}/> <PanelBody content={this.props.content}/> </div> ); } }
若是一个组件的状态或配置较多,咱们能够运用props
传递元素而不只是数据,好比再声明一个组件,使其中的父组件只专一于配置
app
class CommentTemplate extends React.Component { static propTypes = { // Declare slots as type node metadata: PropTypes.node, actions: PropTypes.node, }; render() { return ( <div> <CommentHeading> <Avatar user={...}/> // Slot for metadata <span>{this.props.metadata}</span> </CommentHeading> <CommentBody/> <CommentFooter> <Timestamp time={...}/> // Slot for actions <span>{this.props.actions}</span> </CommentFooter> </div> ); } }
父组件函数
class Comment extends React.Component { render() { const metadata = this.props.publishTime ? <PublishTime time={this.props.publishTime} /> : <span>Saving...</span>; const actions = []; if (this.props.isSignedIn) { actions.push(<LikeAction />); actions.push(<ReplyAction />); } if (this.props.isAuthor) { actions.push(<DeleteAction />); } return <CommentTemplate metadata={metadata} actions={actions} />; } }
实现点击某组件的超连接,发送该组件的 ID,咱们大多的解决方法可能以下工具
class Document extends React.Component { componentDidMount() { ReactDOM.findDOMNode(this).addEventListener('click', this.onClick); } componentWillUnmount() { ReactDOM.findDOMNode(this).removeEventListener('click', this.onClick); } onClick = (e) => { if (e.target.tagName === 'A') { // Naive check for <a> elements sendAnalytics('link clicked', { documentId: this.props.documentId // Specific information to be sent }); } }; render() { // ... } }
然而它却存在代码不能复用
,组件重构困难
等问题测试
咱们可使用高阶组件
来解决这些问题,顾名思义,高阶组件就是一个函数,传给它一个组件,它返回一个新的组件this
function withLinkAnalytics(mapPropsToData, WrappedComponent) { class LinkAnalyticsWrapper extends React.Component { componentDidMount() { ReactDOM.findDOMNode(this).addEventListener('click', this.onClick); } componentWillUnmount() { ReactDOM.findDOMNode(this).removeEventListener('click', this.onClick); } onClick = (e) => { if (e.target.tagName === 'A') { // Naive check for <a> elements const data = mapPropsToData ? mapPropsToData(this.props) : {}; sendAnalytics('link clicked', data); } }; render() { // Simply render the WrappedComponent with all props return <WrappedComponent {...this.props} />; } } return LinkAnalyticsWrapper; }
简化代码以下spa
class Document extends React.Component { render() { // ... } } export default withLinkAnalytics((props) => ({ documentId: props.documentId }), Document);
以上 3 个 React 组件的解耦重构
方法均可以直接拿来运用,最开始可能会以为有点棘手,可是不要紧,只要坚持下来,你就会写出更强壮和可复用的代码code
原文连接
: Techniques for decomposing React components (David Tang)