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)